import { Router, type Request, type Response } from 'express';
import { LicenseService } from '../services/LicenseService';
import SelfUpdateService from '../services/SelfUpdateService';
import { requireAdmin } from '../middleware/tierGates';
import { rejectApiTokenScope } from '../middleware/apiTokenScope';

const LICENSE_SCOPE_MESSAGE = 'API tokens cannot manage licenses.';

export const licenseRouter = Router();

licenseRouter.get('/', (_req: Request, res: Response): void => {
  try {
    const info = LicenseService.getInstance().getLicenseInfo();
    res.json(info);
  } catch (error) {
    console.error('[License] Error getting license info:', error);
    res.status(500).json({ error: 'Failed to retrieve license information' });
  }
});

licenseRouter.post('/activate', async (req: Request, res: Response): Promise<void> => {
  if (rejectApiTokenScope(req, res, LICENSE_SCOPE_MESSAGE)) return;
  if (!requireAdmin(req, res)) return;
  try {
    const { license_key } = req.body;
    if (!license_key || typeof license_key !== 'string') {
      res.status(400).json({ error: 'A valid license key is required' });
      return;
    }
    const result = await LicenseService.getInstance().activate(license_key.trim());
    if (result.success) {
      res.json({ success: true, license: LicenseService.getInstance().getLicenseInfo() });
    } else {
      res.status(400).json({ error: result.error });
    }
  } catch (error) {
    console.error('[License] Activation error:', error);
    res.status(500).json({ error: 'License activation failed' });
  }
});

licenseRouter.post('/deactivate', async (req: Request, res: Response): Promise<void> => {
  if (rejectApiTokenScope(req, res, LICENSE_SCOPE_MESSAGE)) return;
  if (!requireAdmin(req, res)) return;
  try {
    const result = await LicenseService.getInstance().deactivate();
    if (result.success) {
      res.json({ success: true, license: LicenseService.getInstance().getLicenseInfo() });
    } else {
      res.status(500).json({ error: result.error });
    }
  } catch (error) {
    console.error('[License] Deactivation error:', error);
    res.status(500).json({ error: 'License deactivation failed' });
  }
});

licenseRouter.post('/validate', async (_req: Request, res: Response): Promise<void> => {
  try {
    const result = await LicenseService.getInstance().validate();
    res.json({ ...result, license: LicenseService.getInstance().getLicenseInfo() });
  } catch (error) {
    console.error('[License] Validation error:', error);
    res.status(500).json({ error: 'License validation failed' });
  }
});

licenseRouter.get('/billing-portal', async (_req: Request, res: Response): Promise<void> => {
  try {
    const result = await LicenseService.getInstance().getBillingPortalUrl();
    if ('error' in result) {
      res.status(404).json({ error: result.error });
      return;
    }
    res.json({ url: result.url });
  } catch (error) {
    console.error('[License] Billing portal error:', error);
    res.status(500).json({ error: 'Failed to retrieve billing portal URL' });
  }
});

/**
 * Respond 202, then trigger the "last breath" self-update after flush.
 * Exported because the fleet "update this node" route reuses the same
 * response shape + post-flush trigger for local-node self-updates.
 */
export function scheduleLocalUpdate(res: Response, message: string): void {
  res.status(202).json({ message });
  res.on('finish', () => {
    setTimeout(() => {
      // Defense in depth: triggerUpdate records its own errors into
      // lastUpdateError; guard against an unexpected throw becoming an
      // unhandled rejection.
      SelfUpdateService.getInstance().triggerUpdate().catch((err) => {
        console.error('[SelfUpdate] Unexpected error during triggerUpdate:', err);
      });
    }, 500);
  });
}

export const systemUpdateRouter = Router();

systemUpdateRouter.post('/update', (req: Request, res: Response): void => {
  if (!requireAdmin(req, res)) return;
  if (!SelfUpdateService.getInstance().isAvailable()) {
    res.status(503).json({ error: 'Self-update unavailable. Sencho must be deployed via Docker Compose.' });
    return;
  }
  scheduleLocalUpdate(res, 'Update initiated. The server will restart shortly.');
});
