import { Router, Request, Response } from 'express';
import { omnlRateLimiter } from '../middleware/rate-limit';
import { omnlSensitiveRouteGuard, omnlRequireApiKeyInProduction } from '../middleware/omnl-guards';
import { omnlAuditMiddleware } from '../middleware/omnl-audit-middleware';
import { omnlComplianceGateMiddleware } from '../middleware/omnl-compliance-gate';
import { omnlIdempotencyMiddleware } from '../middleware/omnl-idempotency';
import { runTripleStateReconcile } from '../../services/omnl-triple-reconcile';
import { getCachedCashInBankAuditSnapshot } from '../../services/omnl-cash-in-bank-audit';
import { getCachedHoReserveCoverageSnapshot } from '../../services/chain138-ho-reserve-coverage';
import {
  buildIfrs7Disclosure,
  buildIfrs9Disclosure,
  buildIfrs13Disclosure,
  buildIas21Ias37Disclosure,
  buildFullDisclosure,
  getComplianceSignoffsSummary,
} from '../../services/omnl-ifrs-disclosures';
import {
  saveIso20022Message,
  listIso20022Messages,
  getIso20022Message,
  type Iso20022MessageType,
} from '../../services/omnl-iso20022-store';
import { verifyOmnlWebhookSignature } from '../../services/omnl-webhooks';
import { appendOmnlAudit } from '../../services/omnl-audit-log';
import { listOmnlEntities, getOmnlEntity } from '../../services/omnl-entity-registry';
import { validateIso20022Payload } from '../../services/omnl-iso20022-validate';
import { getWeb3ComplianceSummary, buildNotarizationIntent } from '../../services/omnl-web3-compliance';
import {
  buildComplianceConsoleSnapshot,
} from '../../services/omnl-compliance-console';
import { buildSafeNotaryGateTransaction } from '../../services/omnl-safe-notary-gate-tx';
import { readFileSync, existsSync } from 'fs';
import { resolve } from 'path';

const router = Router();
router.use(omnlRateLimiter);
router.use(omnlAuditMiddleware);
router.use(omnlRequireApiKeyInProduction);
router.use(omnlIdempotencyMiddleware);
router.use(omnlComplianceGateMiddleware);

router.get('/omnl/reconcile/triple-state', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    const lineId = String(req.query.lineId || '');
    const report = await runTripleStateReconcile(lineId || undefined);
    res.status(report.aligned ? 200 : 409).json(report);
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    res.status(500).json({ error: msg });
  }
});

router.get('/omnl/cash-in-bank', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    const officeId = req.query.officeId != null ? Number(req.query.officeId) : undefined;
    const totalSupplyUsdRaw = req.query.totalSupplyUsd != null ? Number(req.query.totalSupplyUsd) : undefined;
    const forceRefresh = String(req.query.refresh || '') === '1';
    const totalSupplyUsd =
      totalSupplyUsdRaw != null && Number.isFinite(totalSupplyUsdRaw) && totalSupplyUsdRaw > 0
        ? totalSupplyUsdRaw
        : undefined;
    const snapshot = await getCachedCashInBankAuditSnapshot({
      officeId: Number.isFinite(officeId) ? officeId : undefined,
      totalSupplyUsd,
      forceRefresh,
      lineId: String(req.query.lineId || '') || undefined,
    });
    const status = snapshot.audit.status === 'aligned' ? 200 : snapshot.audit.status === 'unavailable' ? 503 : 409;
    res.status(status).json(snapshot);
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    res.status(500).json({ error: msg });
  }
});

router.get('/omnl/ho-reserve-coverage', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    const officeId = req.query.officeId != null ? Number(req.query.officeId) : undefined;
    const forceRefresh = String(req.query.refresh || '') === '1';
    const snapshot = await getCachedHoReserveCoverageSnapshot({
      officeId: Number.isFinite(officeId) ? officeId : undefined,
      forceRefresh,
    });
    const status = snapshot.status === 'sufficient' ? 200 : snapshot.status === 'unavailable' ? 503 : 409;
    res.status(status).json(snapshot);
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    res.status(500).json({ error: msg });
  }
});

router.get('/omnl/disclosures/ifrs7', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    res.json(await buildIfrs7Disclosure(String(req.query.lineId || '') || undefined));
  } catch (e) {
    res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
  }
});

router.get('/omnl/disclosures/ifrs9', omnlSensitiveRouteGuard, (_req, res) => {
  res.json(buildIfrs9Disclosure());
});

router.get('/omnl/disclosures/ifrs13', omnlSensitiveRouteGuard, (req, res) => {
  res.json(buildIfrs13Disclosure(String(req.query.lineId || '') || undefined));
});

router.get('/omnl/disclosures/ias21-ias37', omnlSensitiveRouteGuard, (_req, res) => {
  res.json(buildIas21Ias37Disclosure());
});

router.get('/omnl/compliance/signoffs', omnlSensitiveRouteGuard, (_req, res) => {
  res.json(getComplianceSignoffsSummary());
});

router.get('/omnl/compliance/web3', omnlSensitiveRouteGuard, (_req, res) => {
  res.json(getWeb3ComplianceSummary());
});

router.get('/omnl/compliance/console', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    const lineId = String(req.query.lineId || '').trim() || undefined;
    res.json(await buildComplianceConsoleSnapshot(lineId));
  } catch (e) {
    res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
  }
});

router.get('/omnl/compliance/safe-notary-gate-tx', omnlSensitiveRouteGuard, (_req, res) => {
  const tx = buildSafeNotaryGateTransaction();
  if (!tx) {
    res.status(404).json({
      error: 'Safe notary gate transaction unavailable',
      hint: 'Set PROXMOX_ROOT and ensure config/compliance/*.v1.json exist',
    });
    return;
  }
  res
    .type('application/json')
    .attachment('omnl-safe-notary-gate-tx.json')
    .send(JSON.stringify(tx, null, 2));
});

router.post('/omnl/compliance/notarization-intent', omnlSensitiveRouteGuard, (req, res) => {
  const body = req.body as {
    jurisdictionId?: string;
    matrixControlId?: string;
    contentHash?: string;
    merkleRoot?: string;
    metadataHash?: string;
  };
  if (!body?.jurisdictionId || !body?.matrixControlId || !body?.contentHash) {
    res.status(400).json({ error: 'jurisdictionId, matrixControlId, contentHash required' });
    return;
  }
  res.json(buildNotarizationIntent({
    jurisdictionId: body.jurisdictionId,
    matrixControlId: body.matrixControlId,
    contentHash: body.contentHash,
    merkleRoot: body.merkleRoot,
    metadataHash: body.metadataHash,
  }));
});

router.get('/omnl/disclosures/full', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  const lineId = String(req.query.lineId || '') || undefined;
  res.json(await buildFullDisclosure(lineId));
});

router.get('/omnl/entities', omnlSensitiveRouteGuard, (_req, res) => {
  res.json(listOmnlEntities());
});

router.get('/omnl/entities/:clientNumber', omnlSensitiveRouteGuard, (req, res) => {
  const n = parseInt(String(req.params.clientNumber), 10);
  const entity = getOmnlEntity(n);
  if (!entity) {
    res.status(404).json({ error: 'not found' });
    return;
  }
  res.json(entity);
});

router.post('/omnl/iso20022/messages', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
  try {
    const body = req.body as {
      messageType?: Iso20022MessageType;
      payload?: string;
      uetr?: string;
      instructionId?: string;
      settlementOrChainRef?: string;
      accountingRef?: string;
    };
    if (!body?.messageType || !body?.payload) {
      res.status(400).json({ error: 'messageType and payload required' });
      return;
    }
    const schema = await validateIso20022Payload(body.messageType, body.payload);
    if (!schema.valid) {
      res.status(400).json({ error: 'iso20022_schema_invalid', details: schema.errors });
      return;
    }
    const record = saveIso20022Message({
      messageType: body.messageType,
      payload: body.payload,
      uetr: body.uetr,
      instructionId: body.instructionId,
      settlementOrChainRef: body.settlementOrChainRef,
      accountingRef: body.accountingRef,
    });
    res.status(201).json(record);
  } catch (e) {
    res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
  }
});

router.get('/omnl/iso20022/messages', omnlSensitiveRouteGuard, (req, res) => {
  const limit = parseInt(String(req.query.limit || '50'), 10);
  res.json({ messages: listIso20022Messages(limit) });
});

router.get('/omnl/iso20022/messages/:id', omnlSensitiveRouteGuard, (req, res) => {
  const r = getIso20022Message(req.params.id as string);
  if (!r) {
    res.status(404).json({ error: 'not found' });
    return;
  }
  res.json(r);
});

router.post('/omnl/webhooks/inbound', (req: Request, res: Response) => {
  const secret = process.env.OMNL_WEBHOOK_SECRET || '';
  const raw = typeof req.body === 'string' ? req.body : JSON.stringify(req.body);
  const sig = req.headers['x-omnl-signature'] as string | undefined;
  if (secret && !verifyOmnlWebhookSignature(raw, sig, secret)) {
    res.status(401).json({ error: 'invalid signature' });
    return;
  }
  appendOmnlAudit({
    category: 'webhook_in',
    action: 'inbound_webhook',
    traceId: (req.body as { deliveryId?: string })?.deliveryId,
    metadata: { bodyPreview: raw.slice(0, 500) },
    status: 'ok',
  });
  res.json({ received: true });
});

router.get('/omnl/roles/matrix', omnlSensitiveRouteGuard, (_req, res) => {
  const root = process.env.PROXMOX_ROOT || process.env.PHOENIX_REPO_ROOT || process.cwd();
  const p = resolve(root, 'config/omnl-fineract-roles.v1.json');
  if (!existsSync(p)) {
    res.status(404).json({ error: 'config/omnl-fineract-roles.v1.json not found' });
    return;
  }
  res.type('application/json').send(readFileSync(p, 'utf8'));
});

export default router;
