import {
  auditLog,
  builds,
  createDb,
  desc,
  eq,
  inArray,
  mcpServers,
  organizations,
  supportMessages,
  supportTickets,
  users,
} from '@bmm/db';
import type { FastifyInstance } from 'fastify';
import { z } from 'zod';
import { audit } from '../lib/audit.js';
import { requireAuth } from '../plugins/session.js';

const db = createDb();

export async function accountRoutes(app: FastifyInstance): Promise<void> {
  // ─── Profile: read + update ───────────────────────────────────────────
  app.get('/v1/account/profile', { preHandler: requireAuth }, async (req, reply) => {
    const user = req.user!;
    const [row] = await db
      .select({
        id: users.id,
        email: users.email,
        name: users.name,
        phone: users.phone,
        isAdmin: users.isAdmin,
        createdAt: users.createdAt,
      })
      .from(users)
      .where(eq(users.id, user.userId))
      .limit(1);
    if (!row) return reply.code(404).send({ error: 'user_not_found' });
    return reply.send({ profile: row });
  });

  app.patch('/v1/account/profile', { preHandler: requireAuth }, async (req, reply) => {
    const user = req.user!;
    const Body = z.object({
      name: z.string().min(1).max(128).optional(),
    });
    const parsed = Body.safeParse(req.body);
    if (!parsed.success) return reply.code(400).send({ error: 'invalid_input' });
    if (!parsed.data.name) return reply.send({ ok: true, changed: false });

    await db
      .update(users)
      .set({ name: parsed.data.name })
      .where(eq(users.id, user.userId));

    await audit({
      orgId: user.orgId,
      userId: user.userId,
      action: 'account.profile_updated',
      resourceType: 'user',
      ipAddress: req.ip,
    });

    return reply.send({ ok: true, changed: true });
  });

  /**
   * GDPR Art. 15 / Swiss DSG Art. 25 — right of access. Returns every record
   * we hold that belongs to the calling user. Excludes hashed passwords,
   * encrypted secret payloads, and any other user's data. Streamed as JSON
   * attachment so the browser downloads it directly.
   */
  app.get('/v1/account/export', { preHandler: requireAuth }, async (req, reply) => {
    const user = req.user!;

    const [userRow] = await db.select().from(users).where(eq(users.id, user.userId)).limit(1);
    const [org] = await db
      .select()
      .from(organizations)
      .where(eq(organizations.id, user.orgId))
      .limit(1);
    const orgServers = await db
      .select()
      .from(mcpServers)
      .where(eq(mcpServers.orgId, user.orgId));
    const serverIds = orgServers.map((s) => s.id);
    const orgBuilds =
      serverIds.length > 0
        ? await db.select().from(builds).where(inArray(builds.serverId, serverIds))
        : [];
    const userAudit = await db
      .select()
      .from(auditLog)
      .where(eq(auditLog.userId, user.userId))
      .orderBy(desc(auditLog.createdAt))
      .limit(1000);
    const userTickets = await db
      .select()
      .from(supportTickets)
      .where(eq(supportTickets.userId, user.userId));
    const ticketIds = userTickets.map((t) => t.id);
    const userTicketMessages =
      ticketIds.length > 0
        ? await db
            .select()
            .from(supportMessages)
            .where(inArray(supportMessages.ticketId, ticketIds))
        : [];

    await audit({
      orgId: user.orgId,
      userId: user.userId,
      action: 'account.export',
      resourceType: 'account',
      ipAddress: req.ip,
    });

    reply
      .header('Content-Type', 'application/json; charset=utf-8')
      .header(
        'Content-Disposition',
        `attachment; filename="buildmymcpserver-export-${Date.now()}.json"`,
      );

    return reply.send({
      exportedAt: new Date().toISOString(),
      _format: 'BuildMyMCPServer Account Export v1',
      _excluded: [
        'password hashes',
        'encrypted secret payloads',
        'session tokens',
        'other users in the same organization',
      ],
      user: userRow
        ? {
            id: userRow.id,
            email: userRow.email,
            name: userRow.name,
            phone: userRow.phone,
            isAdmin: userRow.isAdmin,
            createdAt: userRow.createdAt,
          }
        : null,
      organization: org
        ? {
            id: org.id,
            slug: org.slug,
            name: org.name,
            plan: org.plan,
            createdAt: org.createdAt,
          }
        : null,
      servers: orgServers.map((s) => ({
        id: s.id,
        slug: s.slug,
        name: s.name,
        status: s.status,
        publicUrl: s.publicUrl,
        toolsSchema: s.toolsSchema,
        createdAt: s.createdAt,
      })),
      builds: orgBuilds.map((b) => ({
        id: b.id,
        serverId: b.serverId,
        version: b.version,
        prompt: b.prompt,
        status: b.status,
        createdAt: b.createdAt,
      })),
      audit: userAudit.map((a) => ({
        id: a.id,
        action: a.action,
        resourceType: a.resourceType,
        resourceId: a.resourceId,
        metadata: a.metadata,
        ipAddress: a.ipAddress,
        createdAt: a.createdAt,
      })),
      supportTickets: userTickets,
      supportMessages: userTicketMessages,
    });
  });
}
