/**
 * Admin Licenses Routes
 *
 * Base path: /v1/admin/licenses
 */

import { Router, Request, Response } from 'express';
import { PrismaClient } from '@prisma/client';
import { z } from 'zod';
import { authenticateAdmin } from '../../middleware/auth';
import { AdminRole } from '../../types';
import { validate, validateQuery } from '../../middleware/validator';
import { errorResponse, successResponse } from '../../utils/errorHandler';
import { logger } from '../../utils/logger';
import {
  createLicense,
  getLicenseById,
  updateLicenseStatus,
  extendLicense,
  updateLicenseLimits,
  regenerateLicenseKey,
  adminDeactivateSite,
  listLicenses,
} from '../../services/multilingualLicenseService';

const router = Router();
const prisma = new PrismaClient();

// ---------------------------------------------------------------------------
// Error mapping
// ---------------------------------------------------------------------------

const SERVICE_ERRORS: Record<string, { status: number; code: string; message: string }> = {
  LICENSE_NOT_FOUND:          { status: 404, code: 'LICENSE_NOT_FOUND', message: 'License not found' },
  ACTIVATION_NOT_FOUND:      { status: 404, code: 'ACTIVATION_NOT_FOUND', message: 'Activation not found' },
  CANNOT_REACTIVATE_REVOKED: { status: 409, code: 'CANNOT_REACTIVATE_REVOKED', message: 'Revoked licenses cannot be reactivated. Regenerate the key instead.' },
  NO_FIELDS_TO_UPDATE:       { status: 400, code: 'NO_FIELDS_TO_UPDATE', message: 'No valid fields provided' },

};

function handleServiceError(err: unknown, res: Response, fallbackMessage: string) {
  const msg = err instanceof Error ? err.message : '';
  const mapped = SERVICE_ERRORS[msg];
  if (mapped) {
    return res.status(mapped.status).json(errorResponse(mapped.code, mapped.message));
  }
  logger.error(fallbackMessage, { error: err });
  return res.status(500).json(errorResponse('INTERNAL_ERROR', fallbackMessage));
}

// ---------------------------------------------------------------------------
// Schemas
// ---------------------------------------------------------------------------

const listQuerySchema = z.object({
  page: z.coerce.number().int().min(1).optional(),
  per_page: z.coerce.number().int().min(1).max(100).optional(),
  plugin: z.string().max(20).optional(),
  status: z.string().max(20).optional(),
  plan_tier: z.string().max(50).optional(),
  key_last4: z.string().max(10).optional(),
  sort_by: z.string().max(30).optional(),
  sort_order: z.enum(['asc', 'desc']).optional(),
});

const createSchema = z.object({
  plan_tier: z.string().min(1).max(50),
  sites_allowed: z.number().int().min(-1),
  languages_allowed: z.number().int().min(-1).optional(),
  plugin: z.string().max(20).optional(),
  user_id: z.string().min(1).max(100).optional(),
  execution_mode: z.enum(['live', 'mock']).default('live'),
  expires_at: z.string().min(1),
});

export async function validateMockIssuance(req: Request, res: Response): Promise<boolean> {
  if (req.body.execution_mode !== 'mock') {
    return true;
  }

  if (req.admin?.role !== AdminRole.ADMIN) {
    res.status(403).json(errorResponse('MOCK_LICENSE_ISSUANCE_FORBIDDEN', 'Only administrators can issue mock licenses'));
    return false;
  }

  if (!req.body.user_id) {
    res.status(422).json(errorResponse('MOCK_LICENSE_OWNER_REQUIRED', 'Mock licenses require an explicit owner'));
    return false;
  }

  if (req.body.plugin !== 'international') {
    res.status(403).json(errorResponse('MOCK_LICENSE_ISSUANCE_FORBIDDEN', 'Mock licenses are only available for international'));
    return false;
  }

  const owner = await prisma.user.findUnique({
    where: { id: req.body.user_id },
    select: {
      status: true,
      subscriptions: {
        where: { plugin: 'international', status: 'active' },
        select: { id: true },
      },
    },
  });

  if (!owner) {
    res.status(422).json(errorResponse('MOCK_LICENSE_OWNER_REQUIRED', 'Mock licenses require an existing owner'));
    return false;
  }

  if (owner.status !== 'active') {
    res.status(403).json(errorResponse('MOCK_LICENSE_ISSUANCE_FORBIDDEN', 'Mock license owner account is not active'));
    return false;
  }

  if (owner.subscriptions.length === 0) {
    res.status(403).json(errorResponse('MOCK_LICENSE_ISSUANCE_FORBIDDEN', 'Active international subscription required for mock licenses'));
    return false;
  }

  return true;
}

const updateSchema = z.object({
  status: z.enum(['active', 'suspended', 'expired', 'revoked']).optional(),
  expires_at: z.string().optional(),
  sites_allowed: z.number().int().min(-1).optional(),
  languages_allowed: z.number().int().min(-1).optional(),
}).refine(
  (data) => data.status || data.expires_at || data.sites_allowed !== undefined || data.languages_allowed !== undefined,
  { message: 'At least one field (status, expires_at, sites_allowed, languages_allowed) is required' }
);

// ---------------------------------------------------------------------------
// Routes
// ---------------------------------------------------------------------------

// GET / — paginated list with filters
router.get('/', authenticateAdmin, validateQuery(listQuerySchema), async (req: Request, res: Response) => {
  try {
    const result = await listLicenses(req.query as any);
    return res.status(200).json(successResponse(result));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to list licenses');
  }
});

// POST / — create license
router.post('/', authenticateAdmin, validate(createSchema), async (req: Request, res: Response) => {
  try {
    if (!(await validateMockIssuance(req, res))) {
      return;
    }

    const expires = new Date(req.body.expires_at);
    if (Number.isNaN(expires.getTime())) {
      return res.status(400).json(errorResponse('VALIDATION_ERROR', 'expires_at must be an ISO date string'));
    }

    const created = await createLicense({
      plan_tier: req.body.plan_tier,
      sites_allowed: req.body.sites_allowed,
      expires_at: expires,
      languages_allowed: req.body.languages_allowed,
      plugin: req.body.plugin,
      user_id: req.body.user_id,
      execution_mode: req.body.execution_mode,
    });

    return res.status(201).json(
      successResponse({
        license_key: created.license_key,
        license: created.license,
      })
    );
  } catch (err) {
    return handleServiceError(err, res, 'Failed to create license');
  }
});

// GET /:id — license detail with activations
router.get('/:id', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const license = await getLicenseById(req.params.id);
    return res.status(200).json(successResponse({ license }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to get license');
  }
});

// PATCH /:id — update status, expiry, or limits
router.patch('/:id', authenticateAdmin, validate(updateSchema), async (req: Request, res: Response) => {
  try {
    const { id } = req.params;
    const { status, expires_at, sites_allowed, languages_allowed } = req.body;

    if (status) {
      await updateLicenseStatus(id, status);
    }

    if (expires_at) {
      const date = new Date(expires_at);
      if (Number.isNaN(date.getTime())) {
        return res.status(400).json(errorResponse('VALIDATION_ERROR', 'expires_at must be an ISO date string'));
      }
      await extendLicense(id, date);
    }

    if (sites_allowed !== undefined || languages_allowed !== undefined) {
      await updateLicenseLimits(id, { sites_allowed, languages_allowed });
    }

    // Return fresh license data
    const license = await getLicenseById(id);
    return res.status(200).json(successResponse({ license }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to update license');
  }
});

// POST /:id/revoke
router.post('/:id/revoke', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    await updateLicenseStatus(req.params.id, 'revoked');
    const license = await getLicenseById(req.params.id);
    return res.status(200).json(successResponse({ license }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to revoke license');
  }
});

// POST /:id/suspend
router.post('/:id/suspend', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    await updateLicenseStatus(req.params.id, 'suspended');
    const license = await getLicenseById(req.params.id);
    return res.status(200).json(successResponse({ license }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to suspend license');
  }
});

// POST /:id/reactivate
router.post('/:id/reactivate', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    await updateLicenseStatus(req.params.id, 'active');
    const license = await getLicenseById(req.params.id);
    return res.status(200).json(successResponse({ license }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to reactivate license');
  }
});

// POST /:id/regenerate-key
router.post('/:id/regenerate-key', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    const result = await regenerateLicenseKey(req.params.id);
    return res.status(200).json(successResponse(result));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to regenerate license key');
  }
});

// DELETE /:id/activations/:activationId
router.delete('/:id/activations/:activationId', authenticateAdmin, async (req: Request, res: Response) => {
  try {
    await adminDeactivateSite(req.params.id, req.params.activationId);
    return res.status(200).json(successResponse({ deactivated: true }));
  } catch (err) {
    return handleServiceError(err, res, 'Failed to deactivate site');
  }
});

export default router;
