import { NextRequest, NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth/session";
import { db, isDatabaseAvailable } from "@/lib/db";
import { ensureDatabaseInitialized } from "@/lib/db/init";
import { users, sessions, receipts } from "@/lib/schema/db";
import { eq, gt, and, desc, count } from "drizzle-orm";
import { sanitizeText } from "@/lib/ingest/sanitize";
import { MAX_JSON_BODY_BYTES, FREE_SCAN_LIMIT, LAUNCH_BONUS_SCANS } from "@/lib/limits";
import { readJsonSized } from "@/lib/http/requestSize";
import { requireCsrf } from "@/lib/auth/csrf";
import { bearerTokenFrom, hashToken } from "@/lib/auth/tokens";
import { cookies } from "next/headers";
import { SESSION_COOKIE } from "@/lib/auth/config";
import { isProActive } from "@/lib/billing/access";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

/**
 * GET /api/auth/profile
 * Returns detailed profile, quota, security status, and active sessions for the current user.
 */
export async function GET(req: NextRequest) {
  try {
    const user = await getCurrentUser(req);
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const dbAvailable = await isDatabaseAvailable();
    if (!dbAvailable) {
      return NextResponse.json(
        { error: "Database unavailable" },
        { status: 503 }
      );
    }
    await ensureDatabaseInitialized();

    const isPro = isProActive(user);
    const freeScanAllowance = user.launchBonus ? LAUNCH_BONUS_SCANS : FREE_SCAN_LIMIT;

    // Get current session token hash to identify current session (cookie or
    // bearer — whichever this request actually authenticated with).
    const bearerToken = bearerTokenFrom(req.headers);
    const cookieStore = await cookies();
    const currentRawToken = bearerToken ?? cookieStore.get(SESSION_COOKIE)?.value;
    const currentTokenHash = currentRawToken ? hashToken(currentRawToken) : null;

    // Fetch active non-expired sessions for this user
    const activeSessions = await db
      .select({
        id: sessions.id,
        userAgent: sessions.userAgent,
        createdAt: sessions.createdAt,
        expiresAt: sessions.expiresAt,
      })
      .from(sessions)
      .where(and(eq(sessions.userId, user.id), gt(sessions.expiresAt, new Date())))
      .orderBy(desc(sessions.createdAt))
      .limit(10);

    // Count user's receipts
    const receiptCountResult = await db
      .select({ val: count() })
      .from(receipts)
      .where(eq(receipts.userId, user.id));

    const totalReceipts = Number(receiptCountResult[0]?.val ?? 0);

    return NextResponse.json({
      user: {
        id: user.id,
        name: user.name || "",
        email: user.email || "",
        emailVerified: Boolean(user.emailVerifiedAt),
        isGuest: user.isGuest,
        isPro,
        plan: user.plan,
        cancelAtPeriodEnd: Boolean(user.cancelAtPeriodEnd),
        hasPassword: Boolean(user.passwordHash),
        scanCount: Number(user.scanCount ?? 0),
        scanPeriod: user.scanPeriod,
        launchBonus: Boolean(user.launchBonus),
        freeScanAllowance,
        expiresAt: user.expiresAt?.toISOString() ?? null,
        createdAt: user.createdAt?.toISOString() ?? null,
        company: user.company || "",
        useCase: user.useCase || "",
        onboardingCompletedAt: user.onboardingCompletedAt?.toISOString() ?? null,
        receiptCount: totalReceipts,
      },
      sessions: activeSessions.map((s) => ({
        id: s.id,
        userAgent: s.userAgent || "Unbekanntes Gerät",
        createdAt: s.createdAt.toISOString(),
        expiresAt: s.expiresAt.toISOString(),
        isCurrent: Boolean(currentTokenHash && s.id === currentTokenHash),
      })),
    });
  } catch (error: any) {
    console.error("GET /api/auth/profile error:", error);
    return NextResponse.json(
      { error: error?.message || "Internal server error" },
      { status: 500 }
    );
  }
}

/**
 * PATCH /api/auth/profile
 * Updates the user's profile details (name, company, useCase).
 */
export async function PATCH(req: NextRequest) {
  try {
    const csrfBlocked = requireCsrf(req);
    if (csrfBlocked) return csrfBlocked;

    const user = await getCurrentUser(req);
    if (!user) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const parsed = await readJsonSized<{
      name?: string;
      company?: string;
      useCase?: string;
    }>(req, MAX_JSON_BODY_BYTES);
    if (!parsed.ok) return parsed.response;

    const body = parsed.body ?? {};
    const { name, company, useCase } = body;

    const dbAvailable = await isDatabaseAvailable();
    if (!dbAvailable) {
      return NextResponse.json(
        { error: "Database unavailable" },
        { status: 503 }
      );
    }
    await ensureDatabaseInitialized();

    const sanitized = (v: unknown, cap: number): string | undefined =>
      typeof v === "string" ? sanitizeText(v, cap) : undefined;

    const cleanName = sanitized(name, 160);
    const cleanCompany = sanitized(company, 255);
    const cleanUseCase = sanitized(useCase, 100);

    const updates: Record<string, any> = {
      updatedAt: new Date(),
    };

    if (cleanName !== undefined) updates.name = cleanName;
    if (cleanCompany !== undefined) updates.company = cleanCompany;
    if (cleanUseCase !== undefined) updates.useCase = cleanUseCase;

    await db.update(users).set(updates).where(eq(users.id, user.id));

    return NextResponse.json({
      success: true,
      name: cleanName,
      company: cleanCompany,
      useCase: cleanUseCase,
    });
  } catch (error: any) {
    console.error("PATCH /api/auth/profile error:", error);
    return NextResponse.json(
      { error: error?.message || "Internal server error" },
      { status: 500 }
    );
  }
}
