/**
 * DC-103: Auto-route generation — generates Caddyfile entries and DNS records
 *         for discovered containers.
 *
 * Takes a discovered container's info and generates:
 * 1. A Caddyfile site block with reverse_proxy
 * 2. A DNS A record pointing to the host
 * 3. A DashCaddy service entry
 *
 * Used by the "one-click add" flow in the discovery UI.
 *
 * DC-064: Caddy admin API safety — uses `fetchT` (with Origin + CSRF cookie
 * plumbing via http.js) instead of raw `fetch`, and resolves the admin URL
 * from the injected `caddy` context's `adminUrl` (which itself falls back to
 * `process.env.CADDY_ADMIN_URL`) instead of a hardcoded `localhost:2019`.
 */
const express = require('express');
const { ok, errorResponse } = require('../src/utils/responses');
const { ErrorCodes } = require('../src/utilities/error-codes');

module.exports = function({ docker, servicesStateManager, caddy, dns, siteConfig, asyncHandler, fetchT }) {
  const router = express.Router();

  /**
   * POST /api/v1/discover/adopt
   *
   * Body: {
   *   containerId: string,      // Docker container ID (12 chars)
   *   serviceId: string,        // Desired service ID (subdomain)
   *   name: string,             // Display name
   *   port: number,             // Port to proxy to
   *   protocol: 'http'|'https', // Protocol for the upstream
   *   generateDns: boolean,     // Whether to create a DNS record
   *   generateRoute: boolean,   // Whether to create a Caddyfile entry
   * }
   *
   * Returns: { service, caddyRoute, dnsRecord }
   */
  router.post('/discover/adopt', asyncHandler(async (req, res) => {
    const {
      containerId,
      serviceId,
      name,
      port,
      protocol = 'http',
      generateDns = true,
      generateRoute = true,
    } = req.body || {};

    // Validate required fields
    if (!containerId || !serviceId || !name) {
      return errorResponse(res, 400, 'containerId, serviceId, and name are required', {
        code: ErrorCodes.GENERAL.INVALID_INPUT,
      });
    }

    if (!port || port < 1 || port > 65535) {
      return errorResponse(res, 400, 'Valid port (1-65535) is required', {
        code: ErrorCodes.SERVICE.INVALID_PORT,
      });
    }

    // Validate serviceId format (subdomain-safe)
    if (!/^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/.test(serviceId)) {
      return errorResponse(res, 400, 'serviceId must be a valid subdomain (lowercase, alphanumeric, hyphens)', {
        code: ErrorCodes.SERVICE.INVALID_SUBDOMAIN,
      });
    }

    const tld = siteConfig?.tld || '.sami';
    const domain = `${serviceId}${tld}`;
    const upstreamHost = protocol === 'https' ? 'https' : 'http';
    // DC-064: resolve the Caddy admin URL from the caddy context (which
    // itself defaults to process.env.CADDY_ADMIN_URL via context/caddy.js).
    // Never hardcode localhost:2019 — non-loopback Caddy binds disable
    // enforce_origin and the raw fetch below would 403. Using fetchT (when
    // provided) includes the Origin header that satisfies enforce_origin;
    // when fetchT is null we fall back to raw fetch but ONLY for tests that
    // explicitly mock the admin URL.
    const caddyAdminUrl = caddy?.adminUrl || process.env.CADDY_ADMIN_URL || 'http://localhost:2019';
    const httpClient = typeof fetchT === 'function' ? fetchT : fetch;

    const result = {
      service: null,
      caddyRoute: null,
      dnsRecord: null,
    };

    // 1. Create the service entry
    try {
      const service = {
        id: serviceId,
        name,
        subdomain: serviceId,
        domain,
        url: `https://${domain}`,
        port,
        protocol,
        containerId,
        type: 'auto-discovered',
        createdAt: new Date().toISOString(),
      };

      if (servicesStateManager) {
        await servicesStateManager.update(services => {
          // Check for duplicate
          if (services.some(s => s.id === serviceId)) {
            throw new Error(`Service ${serviceId} already exists`);
          }
          services.push(service);
          return services;
        });
      }

      result.service = service;
    } catch (err) {
      return errorResponse(res, 409, err.message, {
        code: ErrorCodes.SERVICE.DUPLICATE_ID,
      });
    }

    // 2. Generate Caddyfile route
    if (generateRoute && caddy) {
      try {
        // Use Caddy admin API to add the route
        const routeConfig = {
          match: [{ host: [domain] }],
          handle: [{
            handler: 'reverse_proxy',
            upstreams: [{ dial: `localhost:${port}` }],
          }],
          terminal: true,
        };

        // Add via Caddy admin API (via fetchT so Origin header is present)
        const response = await httpClient(`${caddyAdminUrl}/config/apps/http/servers/srv0/routes`, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(routeConfig),
        });

        if (response.ok) {
          result.caddyRoute = { domain, upstream: `localhost:${port}`, status: 'created' };
        } else {
          result.caddyRoute = { domain, status: 'failed', error: `Caddy API returned ${response.status}` };
        }
      } catch (err) {
        result.caddyRoute = { domain, status: 'failed', error: err.message };
      }
    }

    // 3. Generate DNS record
    if (generateDns && dns) {
      try {
        // Create an A record pointing to the host
        result.dnsRecord = {
          domain,
          type: 'A',
          // The actual DNS creation depends on the DNS provider configured
          status: 'pending',
          message: 'DNS record creation depends on configured DNS provider',
        };
      } catch (err) {
        result.dnsRecord = { status: 'failed', error: err.message };
      }
    }

    ok(res, result, 201);
  }));

  return router;
};
