/**
 * Plugin update delivery endpoints.
 *
 * Base path (mounted in server.ts): /v1/international/updates
 */

import { Router, Request, Response } from 'express';
import { z } from 'zod';
import { validate, validateQuery } from '../middleware/validator';
import { errorResponse, successResponse } from '../utils/errorHandler';
import { createRateLimiter } from '../middleware/rateLimiter';
import { mapServiceError } from './multilingualLicense';
import { checkForUpdate, verifyPackage } from '../services/pluginUpdateService';

// Same posture as the sibling licensing validate/status endpoints.
const updateRateLimiter = createRateLimiter(15 * 60 * 1000, 100);

// Pinned from the mount, never from the request: a client-supplied product
// that did not match would surface only as a silent "no update".
const PLUGIN = 'international';
const PRODUCT = 'international-press-zone';

/**
 * The shipped plugin sends no site_url; its User-Agent is
 * "InternationalPressZone/<version>; <site url>".
 */
function resolveSiteUrl(req: Request, explicit?: string): string | null {
  const candidate = explicit ?? String(req.headers['user-agent'] ?? '').split(';').pop() ?? '';

  try {
    return new URL(candidate.trim()).origin;
  } catch {
    return null;
  }
}

const licenseKeySchema = z
  .string()
  .regex(/^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/, 'Invalid license key format');

const checkSchema = z.object({
  license_key: licenseKeySchema,
  version: z.string().min(1).max(20),
  product: z.string().max(50).optional(),
  site_url: z.string().url().optional(),
});

const verifySchema = z.object({
  license_key: licenseKeySchema,
  hash: z.string().regex(/^[0-9a-fA-F]{64}$/, 'hash must be a SHA-256 hex digest'),
  version: z.string().min(1).max(20),
  product: z.string().max(50).optional(),
  site_url: z.string().url().optional(),
});

const router = Router();

async function handleCheck(req: Request, res: Response): Promise<Response> {
  const input = (req.method === 'GET' ? req.query : req.body) as z.infer<typeof checkSchema>;
  const site_url = resolveSiteUrl(req, input.site_url);

  if (!site_url) {
    return res
      .status(403)
      .json(errorResponse('SITE_URL_REQUIRED', 'The requesting site could not be identified'));
  }

  try {
    const result = await checkForUpdate({
      license_key: input.license_key,
      site_url,
      plugin: PLUGIN,
      product: PRODUCT,
      version: input.version,
    });
    return res.status(200).json(successResponse(result));
  } catch (err) {
    if (err instanceof Error && err.message === 'SITE_NOT_ACTIVATED') {
      return res
        .status(403)
        .json(errorResponse('SITE_NOT_ACTIVATED', 'This license is not activated for this site'));
    }
    if (err instanceof Error && err.message === 'UPDATE_STORAGE_UNAVAILABLE') {
      return res
        .status(503)
        .json(errorResponse('UPDATE_STORAGE_UNAVAILABLE', 'Release storage is not configured'));
    }
    const mapped = mapServiceError(err);
    return res.status(mapped.status).json(mapped.body);
  }
}

/**
 * POST /check — the hardened form; the license key stays out of the URL.
 */
router.post('/check', updateRateLimiter, validate(checkSchema), handleCheck);

/**
 * GET /check — transition only. Sites already in the field run the GET client
 * and can only reach the POST client by receiving an update, so dropping GET
 * would strand them permanently. The license key is redacted from request logs.
 */
router.get('/check', updateRateLimiter, validateQuery(checkSchema), handleCheck);

/**
 * POST /verify
 *
 * Fail-closed on the plugin side: answer a definite valid true or false, and
 * never a 200 whose `valid` is absent.
 */
router.post('/verify', updateRateLimiter, validate(verifySchema), async (req: Request, res: Response) => {
  const site_url = resolveSiteUrl(req, req.body.site_url);

  if (!site_url) {
    return res
      .status(403)
      .json(errorResponse('SITE_URL_REQUIRED', 'The requesting site could not be identified'));
  }

  try {
    const result = await verifyPackage({
      license_key: req.body.license_key,
      site_url,
      plugin: PLUGIN,
      product: PRODUCT,
      hash: req.body.hash,
      version: req.body.version,
    });
    return res.status(200).json(successResponse(result));
  } catch (err) {
    if (err instanceof Error && err.message === 'SITE_NOT_ACTIVATED') {
      return res
        .status(403)
        .json(errorResponse('SITE_NOT_ACTIVATED', 'This license is not activated for this site'));
    }
    const mapped = mapServiceError(err);
    return res.status(mapped.status).json(mapped.body);
  }
});

export default router;
