import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth/authOptions';
import { query } from '@/lib/db-postgres';
import { randomUUID } from 'crypto';
import { createRepo, createWebhook, getRepo, listWebhooks, GITEA_ADMIN_USER_EXPORT } from '@/lib/gitea';
import { pushTurborepoScaffold } from '@/lib/scaffold';
import { createProject as createCoolifyProject, createMonorepoAppService } from '@/lib/coolify';
import { provisionTheiaWorkspace } from '@/lib/cloud-run-workspace';
import type { ProjectPhaseData, ProjectPhaseScores } from '@/lib/types/project-artifacts';

const GITEA_ADMIN_USER = GITEA_ADMIN_USER_EXPORT;
const APP_URL = process.env.NEXTAUTH_URL ?? process.env.NEXT_PUBLIC_APP_URL ?? 'https://vibnai.com';
const GITEA_WEBHOOK_SECRET = process.env.GITEA_WEBHOOK_SECRET ?? 'vibn-webhook-secret';

export async function POST(request: Request) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.email) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const email = session.user.email;
    const workspace = email.split('@')[0].toLowerCase().replace(/[^a-z0-9]+/g, '-') + '-account';

    // Upsert user into fs_users — guarantees the FK target exists
    const userData = JSON.stringify({
      email,
      name: session.user.name,
      image: session.user.image,
      workspace,
    });
    const existingUser = await query<{ id: string; data: any }>(
      `SELECT id, data FROM fs_users WHERE data->>'email' = $1 LIMIT 1`,
      [email]
    );
    if (existingUser.length === 0) {
      await query(
        `INSERT INTO fs_users (id, user_id, data) VALUES (gen_random_uuid()::text, $1, $2::jsonb)`,
        [session.user.id, userData]
      );
    } else {
      await query(
        `UPDATE fs_users SET user_id = $1, data = data || $2::jsonb, updated_at = NOW() WHERE id = $3`,
        [session.user.id, userData, existingUser[0].id]
      );
    }

    // Fetch the canonical fs_users row (now guaranteed to exist)
    const users = await query<{ id: string; data: any }>(`
      SELECT id, data FROM fs_users WHERE data->>'email' = $1 LIMIT 1
    `, [email]);

    const firebaseUserId = users[0]!.id;

    const body = await request.json();
    const {
      projectName,
      projectType,
      slug,
      vision,
      product,
      workspacePath,
      chatgptUrl,
      githubRepo,
      githubRepoId,
      githubRepoUrl,
      githubDefaultBranch,
    } = body;

    // Check slug uniqueness
    const existing = await query(`SELECT id FROM fs_projects WHERE slug = $1 LIMIT 1`, [slug]);
    if (existing.length > 0) {
      return NextResponse.json({ error: 'Project slug already exists' }, { status: 400 });
    }

    const projectId = randomUUID();
    const now = new Date().toISOString();

    // ──────────────────────────────────────────────
    // 1. Provision Gitea repo
    // ──────────────────────────────────────────────
    let giteaRepo: string | null = null;
    let giteaRepoUrl: string | null = null;
    let giteaCloneUrl: string | null = null;
    let giteaSshUrl: string | null = null;
    let giteaWebhookId: number | null = null;
    let giteaError: string | null = null;

    try {
      const repoName = slug; // e.g. "taskmaster"
      let repo;

      try {
        repo = await createRepo(repoName, {
          description: `${projectName} — managed by Vibn`,
          private: true,
          auto_init: false,
        });
        console.log(`[API] Gitea repo created: ${GITEA_ADMIN_USER}/${repoName}`);
      } catch (createErr) {
        const msg = createErr instanceof Error ? createErr.message : String(createErr);
        // 409 = repo already exists — link to it instead of failing
        if (msg.includes('409')) {
          console.log(`[API] Gitea repo already exists, linking to ${GITEA_ADMIN_USER}/${repoName}`);
          repo = await getRepo(GITEA_ADMIN_USER, repoName);
          if (!repo) throw new Error(`Repo ${repoName} exists but could not be fetched`);
        } else {
          throw createErr;
        }
      }

      giteaRepo = repo.full_name;          // e.g. "mark/taskmaster"
      giteaRepoUrl = repo.html_url;        // e.g. "https://git.vibnai.com/mark/taskmaster"
      giteaCloneUrl = repo.clone_url;
      giteaSshUrl = repo.ssh_url;

      // Push Turborepo monorepo scaffold as initial commit
      await pushTurborepoScaffold(GITEA_ADMIN_USER, repoName, slug, projectName);
      console.log(`[API] Turborepo scaffold pushed to ${giteaRepo}`);

      // Register webhook — skip if one already points to this project
      const webhookUrl = `${APP_URL}/api/webhooks/gitea?projectId=${projectId}`;
      const existingHooks = await listWebhooks(GITEA_ADMIN_USER, repoName).catch(() => []);
      const alreadyHooked = existingHooks.some(h => h.config.url.includes(projectId));

      if (!alreadyHooked) {
        const hook = await createWebhook(GITEA_ADMIN_USER, repoName, webhookUrl, GITEA_WEBHOOK_SECRET);
        giteaWebhookId = hook.id;
        console.log(`[API] Webhook registered: ${giteaRepo}, id: ${giteaWebhookId}`);
      } else {
        giteaWebhookId = existingHooks.find(h => h.config.url.includes(projectId))?.id ?? null;
        console.log(`[API] Webhook already exists for ${giteaRepo}`);
      }
    } catch (err) {
      // Non-fatal — log and continue. Project is still created.
      giteaError = err instanceof Error ? err.message : String(err);
      console.error('[API] Gitea provisioning failed (non-fatal):', giteaError);
    }

    // ──────────────────────────────────────────────
    // 2. Provision Coolify project + per-app services
    // ──────────────────────────────────────────────
    const APP_BASE_DOMAIN = process.env.APP_BASE_DOMAIN ?? 'vibnai.com';
    const appNames = ['product', 'website', 'admin', 'storybook'] as const;
    const provisionedApps: Array<{
      name: string; path: string; coolifyServiceUuid: string | null; domain: string | null;
    }> = appNames.map(name => ({ name, path: `apps/${name}`, coolifyServiceUuid: null, domain: null }));

    if (giteaCloneUrl) {
      try {
        const coolifyProject = await createCoolifyProject(
          projectName,
          `Vibn project: ${projectName}`
        );

        for (const app of provisionedApps) {
          try {
            const domain = `${app.name}-${slug}.${APP_BASE_DOMAIN}`;
            const service = await createMonorepoAppService({
              projectUuid: coolifyProject.uuid,
              appName: app.name,
              gitRepo: giteaCloneUrl,
              domain,
            });
            app.coolifyServiceUuid = service.uuid;
            app.domain = domain;
            console.log(`[API] Coolify service created: ${app.name} → ${domain}`);
          } catch (appErr) {
            console.error(`[API] Coolify service failed for ${app.name}:`, appErr);
          }
        }
      } catch (coolifyErr) {
        console.error('[API] Coolify project provisioning failed (non-fatal):', coolifyErr);
      }
    }

    // ──────────────────────────────────────────────
    // 3. Provision dedicated Theia workspace
    // ──────────────────────────────────────────────
    let theiaWorkspaceUrl: string | null = null;
    let theiaAppUuid: string | null = null;
    let theiaError: string | null = null;

    try {
      const workspace = await provisionTheiaWorkspace(slug, projectId, giteaRepo);
      theiaWorkspaceUrl = workspace.serviceUrl;
      theiaAppUuid = workspace.serviceName;
      console.log(`[API] Theia workspace provisioned: ${theiaWorkspaceUrl}`);
    } catch (err) {
      theiaError = err instanceof Error ? err.message : String(err);
      console.error('[API] Theia workspace provisioning failed (non-fatal):', theiaError);
    }

    // ──────────────────────────────────────────────
    // 4. Save project record
    // ──────────────────────────────────────────────
    const projectData = {
      id: projectId,
      name: projectName,
      slug,
      userId: firebaseUserId,
      workspace,
      projectType,
      productName: product?.name || projectName,
      productVision: vision || '',
      isForClient: product?.isForClient || false,
      hasLogo: product?.hasLogo || false,
      hasDomain: product?.hasDomain || false,
      hasWebsite: product?.hasWebsite || false,
      hasGithub: !!githubRepo,
      hasChatGPT: !!chatgptUrl,
      workspacePath: workspacePath || null,
      workspaceName: workspacePath ? workspacePath.split('/').pop() : null,
      githubRepo: githubRepo || null,
      githubRepoId: githubRepoId || null,
      githubRepoUrl: githubRepoUrl || null,
      githubDefaultBranch: githubDefaultBranch || null,
      chatgptUrl: chatgptUrl || null,
      extensionLinked: false,
      status: 'active',
      currentPhase: 'collector',
      phaseStatus: 'not_started',
      phaseData: {} as ProjectPhaseData,
      phaseScores: {} as ProjectPhaseScores,
      // Gitea provisioning
      giteaRepo,
      giteaRepoUrl,
      giteaCloneUrl,
      giteaSshUrl,
      giteaWebhookId,
      giteaError,
      // Theia workspace
      theiaWorkspaceUrl,
      theiaAppUuid,
      theiaError,
      // Context snapshot (kept fresh by webhooks)
      contextSnapshot: null,
      // Turborepo monorepo apps — each gets its own Coolify service
      turboVersion: '2.3.3',
      apps: provisionedApps,
      createdAt: now,
      updatedAt: now,
    };

    await query(`
      INSERT INTO fs_projects (id, data, user_id, workspace, slug)
      VALUES ($1, $2::jsonb, $3, $4, $5)
    `, [projectId, JSON.stringify(projectData), firebaseUserId, workspace, slug]);

    // Associate any unlinked sessions for this workspace path
    if (workspacePath) {
      await query(`
        UPDATE fs_sessions
        SET data = jsonb_set(
          jsonb_set(data, '{projectId}', $1::jsonb),
          '{needsProjectAssociation}', 'false'
        )
        WHERE user_id = $2
          AND data->>'workspacePath' = $3
          AND (data->>'needsProjectAssociation')::boolean = true
      `, [JSON.stringify(projectId), firebaseUserId, workspacePath]);
    }

    console.log('[API] Created project', projectId, slug, '| gitea:', giteaRepo ?? 'skipped');

    return NextResponse.json({
      success: true,
      projectId,
      slug,
      workspace,
      gitea: giteaRepo
        ? { repo: giteaRepo, repoUrl: giteaRepoUrl, cloneUrl: giteaCloneUrl, sshUrl: giteaSshUrl }
        : null,
      giteaError: giteaError ?? undefined,
      theiaWorkspaceUrl,
      theiaError: theiaError ?? undefined,
    });
  } catch (error) {
    console.error('[POST /api/projects/create] Error:', error);
    return NextResponse.json(
      { error: 'Failed to create project', details: error instanceof Error ? error.message : String(error) },
      { status: 500 }
    );
  }
}
