import type { FastifyInstance } from 'fastify';
import { extractAuth } from '../../lib/auth.js';
import { BadRequestError } from '../../lib/errors.js';
import { CreateIncidentSchema, UpdateIncidentSchema } from './types.js';
import type { IncidentDoc, IncidentUpdate } from './types.js';
import * as repo from './repository.js';
import { checkAllServices } from './health-checker.js';
import { getDependencyHealthReport, getSelfTestReport } from './self-test.js';

const DEFAULT_PRODUCT_ID = 'lysnrai';

function renderSelfTestPage(): string {
  return `<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Platform Self-Test</title>
    <style>
      :root {
        color-scheme: light;
        --bg: #f7f4ec;
        --panel: #fffdf8;
        --ink: #1f2933;
        --muted: #52606d;
        --ok: #1f7a3d;
        --fail: #b42318;
        --border: #d9d3c4;
      }
      body {
        margin: 0;
        padding: 24px;
        background: linear-gradient(180deg, #f7f4ec 0%, #f2efe6 100%);
        color: var(--ink);
        font: 16px/1.5 "Iosevka Web", "IBM Plex Sans", sans-serif;
      }
      main {
        max-width: 960px;
        margin: 0 auto;
      }
      h1 {
        margin: 0 0 8px;
        font-size: 32px;
      }
      .lead {
        margin: 0 0 24px;
        color: var(--muted);
      }
      .toolbar {
        display: flex;
        gap: 12px;
        align-items: center;
        margin-bottom: 24px;
        flex-wrap: wrap;
      }
      button {
        border: 1px solid var(--ink);
        background: var(--ink);
        color: white;
        padding: 10px 14px;
        cursor: pointer;
        font: inherit;
      }
      .panel {
        background: var(--panel);
        border: 1px solid var(--border);
        padding: 16px;
        margin-bottom: 16px;
      }
      .status-ok { color: var(--ok); }
      .status-fail { color: var(--fail); }
      code, pre {
        font: 13px/1.45 "Iosevka Web", "IBM Plex Mono", monospace;
      }
      pre {
        margin: 0;
        overflow: auto;
      }
      table {
        width: 100%;
        border-collapse: collapse;
      }
      th, td {
        text-align: left;
        padding: 8px 0;
        border-bottom: 1px solid var(--border);
        vertical-align: top;
      }
      .pill {
        display: inline-block;
        border: 1px solid currentColor;
        border-radius: 999px;
        padding: 2px 8px;
        font-size: 12px;
      }
    </style>
  </head>
  <body>
    <main>
      <h1>Platform Self-Test</h1>
      <p class="lead">Runs dependency checks plus a real blob upload, download, signed URL, and cleanup cycle.</p>
      <div class="toolbar">
        <button id="rerun" type="button">Run Self-Test</button>
        <a href="/api/health/dependencies">Dependency JSON</a>
        <a href="/api/self-test.json">Self-Test JSON</a>
      </div>
      <section class="panel">
        <strong>Summary:</strong>
        <span id="summary">Loading…</span>
      </section>
      <section class="panel">
        <h2>Dependency Checks</h2>
        <div id="checks">Loading…</div>
      </section>
      <section class="panel">
        <h2>Service Status</h2>
        <div id="services">Loading…</div>
      </section>
      <section class="panel">
        <h2>Raw JSON</h2>
        <pre id="raw">Loading…</pre>
      </section>
    </main>
    <script>
      const summary = document.getElementById('summary');
      const checks = document.getElementById('checks');
      const services = document.getElementById('services');
      const raw = document.getElementById('raw');
      const button = document.getElementById('rerun');

      function statusClass(value) {
        return value === 'ok' || value === 'pass' || value === 'operational' ? 'status-ok' : 'status-fail';
      }

      function renderChecks(items) {
        return '<table><thead><tr><th>Name</th><th>Status</th><th>Summary</th><th>Duration</th></tr></thead><tbody>' +
          items.map(item =>
            '<tr>' +
              '<td><code>' + item.name + '</code></td>' +
              '<td><span class="pill ' + statusClass(item.status) + '">' + item.status + '</span></td>' +
              '<td>' + item.summary + (item.error ? '<br><code>' + item.error + '</code>' : '') + '</td>' +
              '<td>' + item.durationMs + 'ms</td>' +
            '</tr>'
          ).join('') +
          '</tbody></table>';
      }

      function renderServices(items) {
        return '<table><thead><tr><th>Name</th><th>Health</th><th>URL</th><th>Response</th></tr></thead><tbody>' +
          items.map(item =>
            '<tr>' +
              '<td>' + item.name + '</td>' +
              '<td><span class="pill ' + statusClass(item.health) + '">' + item.health + '</span></td>' +
              '<td><code>' + item.url + '</code></td>' +
              '<td>' + (item.responseTimeMs === null ? 'n/a' : item.responseTimeMs + 'ms') + (item.error ? '<br><code>' + item.error + '</code>' : '') + '</td>' +
            '</tr>'
          ).join('') +
          '</tbody></table>';
      }

      async function load() {
        button.disabled = true;
        summary.textContent = 'Running…';
        try {
          const response = await fetch('/api/self-test.json');
          const data = await response.json();
          summary.innerHTML = '<span class="pill ' + statusClass(data.status) + '">' + data.status + '</span> checked at ' + data.checkedAt;
          checks.innerHTML = renderChecks(data.dependencyChecks);
          services.innerHTML = renderServices(data.serviceStatus.services);
          raw.textContent = JSON.stringify(data, null, 2);
        } catch (error) {
          const message = error instanceof Error ? error.message : String(error);
          summary.innerHTML = '<span class="pill status-fail">fail</span> ' + message;
          checks.innerHTML = '';
          services.innerHTML = '';
          raw.textContent = message;
        } finally {
          button.disabled = false;
        }
      }

      button.addEventListener('click', load);
      load();
    </script>
  </body>
</html>`;
}

export async function statusRoutes(app: FastifyInstance) {
  // ── Public endpoints (no auth) ─────────────────────────────

  app.get('/health/dependencies', async (_req, reply) => {
    const report = await getDependencyHealthReport();
    if (report.status !== 'ok') {
      reply.code(503);
    }
    return report;
  });

  app.get('/self-test.json', async (_req, reply) => {
    const report = await getSelfTestReport();
    if (report.status !== 'ok') {
      reply.code(503);
    }
    return report;
  });

  app.get('/self-test', async (_req, reply) => {
    reply.type('text/html; charset=utf-8');
    return renderSelfTestPage();
  });

  // Get current platform status (health checks all services)
  app.get('/status', async () => {
    return checkAllServices();
  });

  // Get active incidents
  app.get('/status/incidents', async () => {
    return repo.listActiveIncidents(DEFAULT_PRODUCT_ID);
  });

  // Get incident by ID
  app.get('/status/incidents/:id', async req => {
    const { id } = req.params as { id: string };
    return repo.getIncident(id, DEFAULT_PRODUCT_ID);
  });

  // Get incident history (all incidents, paginated)
  app.get('/status/history', async req => {
    const limit = parseInt((req.query as Record<string, string>).limit || '20', 10);
    return repo.listIncidents(DEFAULT_PRODUCT_ID, Math.min(limit, 100));
  });

  // ── Admin endpoints (auth required) ────────────────────────

  // Create a new incident
  app.post('/status/incidents', async (req, reply) => {
    await extractAuth(req);
    const parsed = CreateIncidentSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const now = new Date().toISOString();
    const doc: IncidentDoc = {
      id: `inc_${crypto.randomUUID()}`,
      productId: DEFAULT_PRODUCT_ID,
      title: parsed.data.title,
      severity: parsed.data.severity,
      status: 'investigating',
      affectedServices: parsed.data.affectedServices,
      updates: [
        {
          status: 'investigating',
          message: parsed.data.message,
          createdAt: now,
        },
      ],
      createdAt: now,
      updatedAt: now,
    };

    const created = await repo.createIncident(doc);
    return reply.status(201).send(created);
  });

  // Update an incident (add update, change status/severity)
  app.put('/status/incidents/:id', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const parsed = UpdateIncidentSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const existing = await repo.getIncident(id, DEFAULT_PRODUCT_ID);
    const now = new Date().toISOString();
    const updates = parsed.data;

    // Add new update entry if message provided
    const newUpdates: IncidentUpdate[] = [...existing.updates];
    if (updates.message) {
      newUpdates.push({
        status: updates.status || existing.status,
        message: updates.message,
        createdAt: now,
      });
    }

    const updated: IncidentDoc = {
      ...existing,
      status: updates.status || existing.status,
      severity: updates.severity || existing.severity,
      updates: newUpdates,
      updatedAt: now,
      resolvedAt: updates.status === 'resolved' ? now : existing.resolvedAt,
    };

    return repo.updateIncident(updated);
  });
}
