import type { PrismaClient } from "@prisma/client";
import type { FastifyInstance } from "fastify";
import {
  addTeamMember,
  archiveTeam,
  createTeam,
  listOrgTeams,
  listTeamMembers,
  revokeTeamMember,
  updateTeam,
} from "../../org/teams.js";
import { requireOrgRole, type GuardDeps } from "../auth/guards.js";
import { handleRouteError } from "../errors.js";

export async function registerTeamsRoutes(
  app: FastifyInstance,
  config: { readonly prisma: PrismaClient; readonly sessionSecret: string },
): Promise<void> {
  const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret };

  // Read-only listing is open to any active org member so project MANAGE
  // holders can pick a team when granting TEAM→PROJECT access (ADR-0004).
  // Mutations below stay org-admin only.
  app.get("/api/org/:orgSlug/teams", async (request, reply) => {
    try {
      const { orgSlug } = request.params as { orgSlug: string };
      const auth = await requireOrgRole(request, reply, guardDeps, {
        orgSlug,
        roles: ["OWNER", "ADMIN", "MEMBER"],
      });
      if (auth === null) return;
      return { teams: await listOrgTeams(config.prisma, auth.organization.id) };
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.post("/api/org/:orgSlug/teams", async (request, reply) => {
    try {
      const { orgSlug } = request.params as { orgSlug: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const body = (request.body ?? {}) as { slug?: unknown; name?: unknown; description?: unknown };
      if (typeof body.slug !== "string" || typeof body.name !== "string") {
        return reply.status(400).send({
          error: { code: "bad_request", message: "slug and name are required" },
        });
      }
      const team = await createTeam(config.prisma, {
        organizationId: auth.organization.id,
        slug: body.slug,
        name: body.name,
        ...(typeof body.description === "string" ? { description: body.description } : {}),
      });
      return reply.status(201).send(team);
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.patch("/api/org/:orgSlug/teams/:teamId", async (request, reply) => {
    try {
      const { orgSlug, teamId } = request.params as { orgSlug: string; teamId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const body = request.body as { name?: unknown; description?: unknown };
      return await updateTeam(config.prisma, {
        organizationId: auth.organization.id,
        teamId,
        ...(typeof body.name === "string" ? { name: body.name } : {}),
        ...(body.description === null || typeof body.description === "string"
          ? { description: body.description as string | null }
          : {}),
      });
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.post("/api/org/:orgSlug/teams/:teamId/archive", async (request, reply) => {
    try {
      const { orgSlug, teamId } = request.params as { orgSlug: string; teamId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return await archiveTeam(config.prisma, {
        organizationId: auth.organization.id,
        teamId,
      });
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.get("/api/org/:orgSlug/teams/:teamId/members", async (request, reply) => {
    try {
      const { orgSlug, teamId } = request.params as { orgSlug: string; teamId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return {
        members: await listTeamMembers(config.prisma, {
          organizationId: auth.organization.id,
          teamId,
        }),
      };
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.post("/api/org/:orgSlug/teams/:teamId/members", async (request, reply) => {
    try {
      const { orgSlug, teamId } = request.params as { orgSlug: string; teamId: string };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      const body = request.body as { userId?: unknown; feishuOpenId?: unknown };
      const member = await addTeamMember(config.prisma, {
        organizationId: auth.organization.id,
        teamId,
        ...(typeof body.userId === "string" ? { userId: body.userId } : {}),
        ...(typeof body.feishuOpenId === "string" ? { feishuOpenId: body.feishuOpenId } : {}),
      });
      return reply.status(201).send(member);
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });

  app.post("/api/org/:orgSlug/teams/:teamId/members/:userId/revoke", async (request, reply) => {
    try {
      const { orgSlug, teamId, userId } = request.params as {
        orgSlug: string;
        teamId: string;
        userId: string;
      };
      const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
      if (auth === null) return;
      return await revokeTeamMember(config.prisma, {
        organizationId: auth.organization.id,
        teamId,
        userId,
      });
    } catch (err) {
      return handleRouteError(reply, err);
    }
  });
}
