import { http, HttpResponse } from "msw";
import { loginSchema, registerSchema } from "@rubis/shared";
import { mockDb } from "../db";
import { sessionStore } from "../sessionStore";

const apiBase = "*/api/v1";

/** Faux access token signé "à la main" — pas de vraie crypto. */
function fakeToken(userId: string): string {
  return `mock.${userId}.${Date.now()}`;
}

function expiresInMinutes(min: number): string {
  return new Date(Date.now() + min * 60_000).toISOString();
}

/** Extrait l'userId depuis un fake token. Renvoie undefined si invalide. */
export function userIdFromAuthHeader(authHeader: string | null): string | undefined {
  if (!authHeader?.startsWith("Bearer mock.")) return undefined;
  const userId = authHeader.split(".")[1];
  return userId && userId.length > 0 ? userId : undefined;
}

export const authHandlers = [
  // POST /api/v1/auth/login
  http.post(`${apiBase}/auth/login`, async ({ request }) => {
    const json = await request.json();
    const parsed = loginSchema.safeParse(json);
    if (!parsed.success) {
      return HttpResponse.json(
        {
          errors: parsed.error.issues.map((i) => ({
            code: "validation_failed",
            message: i.message,
            field: i.path.join("."),
          })),
        },
        { status: 422 },
      );
    }
    const user = mockDb.findUserByEmail(parsed.data.email);
    if (!user || user.passwordHash !== parsed.data.password) {
      return HttpResponse.json(
        {
          errors: [
            { code: "invalid_credentials", message: "Email ou mot de passe incorrect" },
          ],
        },
        { status: 401 },
      );
    }
    const { passwordHash: _ph, ...publicUser } = user;
    const session = {
      accessToken: fakeToken(user.id),
      expiresAt: expiresInMinutes(30),
      user: publicUser,
    };
    // Persiste la session — simule le cookie httpOnly côté serveur, pour
    // que le SPA puisse la récupérer au boot via /auth/refresh.
    sessionStore.set(session);
    return HttpResponse.json({ data: session });
  }),

  // POST /api/v1/auth/signup
  http.post(`${apiBase}/auth/signup`, async ({ request }) => {
    const json = await request.json();
    const parsed = registerSchema.safeParse(json);
    if (!parsed.success) {
      return HttpResponse.json(
        {
          errors: parsed.error.issues.map((i) => ({
            code: "validation_failed",
            message: i.message,
            field: i.path.join("."),
          })),
        },
        { status: 422 },
      );
    }
    if (mockDb.findUserByEmail(parsed.data.email)) {
      return HttpResponse.json(
        {
          errors: [
            {
              code: "email_taken",
              message: "Cet email est déjà utilisé",
              field: "email",
            },
          ],
        },
        { status: 422 },
      );
    }
    const user = mockDb.createUser(parsed.data);
    const session = {
      accessToken: fakeToken(user.id),
      expiresAt: expiresInMinutes(30),
      user,
    };
    sessionStore.set(session);
    return HttpResponse.json({ data: session }, { status: 201 });
  }),

  // POST /api/v1/auth/refresh — relit la session persistée par MSW.
  // Renouvelle l'accessToken (TTL court) tout en gardant le user.
  http.post(`${apiBase}/auth/refresh`, () => {
    const stored = sessionStore.get();
    if (!stored) {
      return HttpResponse.json(
        { errors: [{ code: "no_session", message: "Pas de session active" }] },
        { status: 401 },
      );
    }
    // Recharge le user depuis mockDb au cas où il a été modifié (onboarding,
    // signature mise à jour, etc.) — sinon le SPA verrait un user stale.
    const fresh = mockDb.findUserById(stored.user.id);
    if (!fresh) {
      sessionStore.clear();
      return HttpResponse.json(
        { errors: [{ code: "no_session", message: "Utilisateur introuvable" }] },
        { status: 401 },
      );
    }
    const { passwordHash: _ph, ...publicUser } = fresh;
    const session = {
      accessToken: fakeToken(publicUser.id),
      expiresAt: expiresInMinutes(30),
      user: publicUser,
    };
    sessionStore.set(session);
    return HttpResponse.json({ data: session });
  }),

  // POST /api/v1/account/logout — clean disconnect
  http.post(`${apiBase}/account/logout`, () => {
    sessionStore.clear();
    return new HttpResponse(null, { status: 204 });
  }),

  // GET /api/v1/account/profile
  http.get(`${apiBase}/account/profile`, ({ request }) => {
    const userId = userIdFromAuthHeader(request.headers.get("authorization"));
    if (!userId) {
      return HttpResponse.json(
        { errors: [{ code: "unauthenticated", message: "Non authentifié" }] },
        { status: 401 },
      );
    }
    const user = mockDb.findUserById(userId);
    if (!user) {
      return HttpResponse.json(
        { errors: [{ code: "not_found", message: "Utilisateur introuvable" }] },
        { status: 404 },
      );
    }
    const { passwordHash: _ph, ...publicUser } = user;
    return HttpResponse.json({ data: publicUser });
  }),
];
