/**
 * POST /api/webhooks/gitea?projectId={projectId}
 *
 * Receives push, pull_request, issues, and issue_comment events from Gitea.
 * Verifies the HMAC signature, then updates the project's contextSnapshot
 * in Postgres so the AI always has fresh context at the start of new chats.
 */

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db-postgres';
import { verifyWebhookSignature } from '@/lib/gitea';

const GITEA_WEBHOOK_SECRET = process.env.GITEA_WEBHOOK_SECRET ?? 'vibn-webhook-secret';

// ──────────────────────────────────────────────────
// Gitea payload shapes (minimal — we only read what we need)
// ──────────────────────────────────────────────────

interface GitCommit {
  id: string;
  message: string;
  timestamp: string;
  author: { name: string; email: string };
  url: string;
}

interface PushPayload {
  ref: string;
  after: string;
  commits: GitCommit[];
  repository: { full_name: string; html_url: string };
  pusher: { login: string };
}

interface PullRequestPayload {
  action: string; // opened, closed, reopened, synchronized
  number: number;
  pull_request: {
    title: string;
    html_url: string;
    state: string;
    merged: boolean;
    head: { label: string };
    base: { label: string };
  };
  repository: { full_name: string };
}

interface IssuePayload {
  action: string; // opened, closed, reopened
  issue: {
    number: number;
    title: string;
    html_url: string;
    state: string;
    body?: string;
    labels?: { name: string }[];
  };
  repository: { full_name: string };
}

// ──────────────────────────────────────────────────
// Handler
// ──────────────────────────────────────────────────

export async function POST(request: NextRequest) {
  const projectId = request.nextUrl.searchParams.get('projectId');
  if (!projectId) {
    return NextResponse.json({ error: 'Missing projectId' }, { status: 400 });
  }

  const rawBody = await request.text();
  const signature = request.headers.get('x-gitea-signature-256') ?? '';
  const event = request.headers.get('x-gitea-event') ?? 'unknown';

  // Verify HMAC signature
  const valid = await verifyWebhookSignature(rawBody, signature, GITEA_WEBHOOK_SECRET);
  if (!valid) {
    console.warn(`[webhook/gitea] Invalid signature for project ${projectId}`);
    return NextResponse.json({ error: 'Invalid signature' }, { status: 401 });
  }

  let payload: any;
  try {
    payload = JSON.parse(rawBody);
  } catch {
    return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
  }

  // Fetch existing project snapshot
  const rows = await query<{ id: string; data: any }>(
    `SELECT id, data FROM fs_projects WHERE id = $1 LIMIT 1`,
    [projectId]
  );

  if (rows.length === 0) {
    console.warn(`[webhook/gitea] Project not found: ${projectId}`);
    return NextResponse.json({ error: 'Project not found' }, { status: 404 });
  }

  const project = rows[0];
  const existingSnapshot = project.data?.contextSnapshot ?? {};

  // Build updated snapshot based on event type
  const updatedAt = new Date().toISOString();
  let snapshotPatch: Record<string, any> = { updatedAt };

  if (event === 'push') {
    const push = payload as PushPayload;
    const branch = push.ref?.replace('refs/heads/', '') ?? 'unknown';
    const latestCommit = push.commits?.[0];

    snapshotPatch.lastCommit = latestCommit
      ? {
          sha: latestCommit.id,
          message: latestCommit.message,
          author: latestCommit.author?.name,
          timestamp: latestCommit.timestamp,
          url: latestCommit.url,
        }
      : existingSnapshot.lastCommit;

    snapshotPatch.currentBranch = branch;
    snapshotPatch.recentCommits = [
      ...(push.commits ?? []).slice(0, 5).map(c => ({
        sha: c.id.slice(0, 8),
        message: c.message.split('\n')[0],
        author: c.author?.name,
        timestamp: c.timestamp,
      })),
      ...(existingSnapshot.recentCommits ?? []),
    ].slice(0, 10);

    console.log(`[webhook/gitea] push to ${branch} on project ${projectId}`);
  } else if (event === 'pull_request') {
    const pr = payload as PullRequestPayload;
    const openPRs: any[] = existingSnapshot.openPRs ?? [];

    if (pr.action === 'opened' || pr.action === 'reopened') {
      // Add or update
      const existing = openPRs.findIndex((p: any) => p.number === pr.number);
      const entry = {
        number: pr.number,
        title: pr.pull_request.title,
        url: pr.pull_request.html_url,
        state: pr.pull_request.state,
        from: pr.pull_request.head.label,
        into: pr.pull_request.base.label,
      };
      if (existing >= 0) openPRs[existing] = entry;
      else openPRs.push(entry);
    } else if (pr.action === 'closed') {
      // Remove closed/merged PR from open list
      const idx = openPRs.findIndex((p: any) => p.number === pr.number);
      if (idx >= 0) openPRs.splice(idx, 1);
    }

    snapshotPatch.openPRs = openPRs;
    console.log(`[webhook/gitea] PR #${pr.number} ${pr.action} on project ${projectId}`);
  } else if (event === 'issues') {
    const iss = payload as IssuePayload;
    const openIssues: any[] = existingSnapshot.openIssues ?? [];

    if (iss.action === 'opened' || iss.action === 'reopened') {
      const existing = openIssues.findIndex((i: any) => i.number === iss.issue.number);
      const entry = {
        number: iss.issue.number,
        title: iss.issue.title,
        url: iss.issue.html_url,
        state: iss.issue.state,
        labels: (iss.issue.labels ?? []).map(l => l.name),
      };
      if (existing >= 0) openIssues[existing] = entry;
      else openIssues.push(entry);
    } else if (iss.action === 'closed') {
      const idx = openIssues.findIndex((i: any) => i.number === iss.issue.number);
      if (idx >= 0) openIssues.splice(idx, 1);
    }

    snapshotPatch.openIssues = openIssues;
    console.log(`[webhook/gitea] issue #${iss.issue.number} ${iss.action} on project ${projectId}`);
  }

  // Merge patch into existing snapshot and persist
  const newSnapshot = { ...existingSnapshot, ...snapshotPatch };

  await query(`
    UPDATE fs_projects
    SET data = jsonb_set(data, '{contextSnapshot}', $1::jsonb)
    WHERE id = $2
  `, [JSON.stringify(newSnapshot), projectId]);

  return NextResponse.json({ ok: true, event, projectId });
}
