import { NextResponse } from "next/server";
import { sql } from "@/db";
import { cookies } from "next/headers";
import bcrypt from "bcryptjs";
import { randomBytes } from "crypto";
import { rateLimit, getClientIp, getRateLimitKey } from "@/lib/rate-limit";
import { logAudit } from "@/lib/audit";
import { sendVerificationEmail } from "@/lib/email";

export const dynamic = "force-dynamic";

// GET - check current session
export async function GET(request: Request) {
  try {
    const cookieStore = await cookies();
    const sessionToken = cookieStore.get("tia_session")?.value;

    if (!sessionToken) {
      return NextResponse.json({ authenticated: false });
    }

    // Verify session
    const sessions = await sql`
      SELECT s.user_id, s.expires, u.email, fm.family_id as family_id
      FROM sessions s
      JOIN users u ON u.id = s.user_id
      LEFT JOIN family_members fm ON fm.user_id::text = s.user_id::text
      WHERE s.session_token = ${sessionToken}
      AND s.expires > NOW()
      LIMIT 1
    `;

    if (!sessions || sessions.length === 0) {
      return NextResponse.json({ authenticated: false });
    }

    const session = sessions[0];
    let family = null;

    if (session.family_id) {
      const families = await sql`
        SELECT id, name, tier, max_children, max_members
        FROM families WHERE id = ${session.family_id}
      `;
      family = families?.[0];
    }

    return NextResponse.json({
      authenticated: true,
      userId: session.user_id,
      email: session.email,
      familyId: session.family_id,
      familyName: family?.name,
      tier: family?.tier,
    });
  } catch (error) {
    console.error("Session check error:", error);
    return NextResponse.json({ authenticated: false });
  }
}

// bcrypt password functions
async function hashPassword(password: string): Promise<string> {
  return await bcrypt.hash(password, 12);
}

async function verifyPassword(password: string, hash: string): Promise<boolean> {
  // Handle old hash format (migrate to bcrypt on success)
  if (hash.startsWith("hash_")) {
    return hashPassword(password).then(h => h === hash).catch(() => false);
  }
  return await bcrypt.compare(password, hash);
}

export async function POST(request: Request) {
  const body = await request.json();
  const { email, password, action } = body;

  if (!email || !password) {
    return NextResponse.json({ error: "Email and password required" }, { status: 400 });
  }

  // Rate limiting - enable via RATE_LIMIT_ENABLED env var
  if (process.env.RATE_LIMIT_ENABLED !== "false") {
    const ip = getClientIp(request);
    const isSignup = action === "signup";
    const rateLimitResult = await rateLimit(
      isSignup ? getRateLimitKey("auth-signup", ip) : getRateLimitKey("auth-signin", ip),
      { max: isSignup ? 3 : 5, windowSec: isSignup ? 3600 : 900 }
    );
    if (!rateLimitResult.success) {
      return NextResponse.json({ error: "Too many attempts" }, { status: 429 });
    }
  }

  try {
    // Find user
    const users = await sql`
      SELECT u.id, u.email, u.password_hash, u.email_verified, fm.family_id as family_id
      FROM users u
      LEFT JOIN family_members fm ON fm.user_id::text = u.id::text
      WHERE u.email = ${email}
      LIMIT 1
    `;

    const user = users?.[0];

    // Sign up - create new account
    if (action === "signup") {
      if (user) {
        return NextResponse.json({ error: "Email already exists" }, { status: 400 });
      }
      const newUserId = crypto.randomUUID();
      const passwordHash = await hashPassword(password);

      // Create the user UNVERIFIED. No tia_session is set here anymore —
      // the user is logged in only after clicking the verification link.
      await sql`
        INSERT INTO users (id, email, password_hash, password_updated_at, created_at, updated_at)
        VALUES (${newUserId}, ${email}, ${passwordHash}, NOW(), NOW(), NOW())
      `;
      await logAudit({ userId: newUserId, action: "signup", request });

      // Single-use verification token, 24h validity.
      const verifyToken = randomBytes(32).toString("hex");
      const expiresAt = new Date();
      expiresAt.setHours(expiresAt.getHours() + 24);
      await sql`
        INSERT INTO email_verifications (user_id, token, expires_at)
        VALUES (${newUserId}, ${verifyToken}, ${expiresAt.toISOString()})
      `;
      await sendVerificationEmail(email, verifyToken, newUserId);

      return NextResponse.json({ success: true, needsVerification: true, email });
    }

    // Sign in - require existing user with password
    if (!user) {
      return NextResponse.json({ error: "User not found" }, { status: 404 });
    }

    if (!user.password_hash) {
      return NextResponse.json({ error: "Set password first at /login", status: 400 });
    }

    const valid = await verifyPassword(password, user.password_hash);
    if (!valid) {
      // Audit log
      await logAudit({
        userId: user.id,
        action: "login_failed",
        request,
        metadata: { reason: "invalid_password" },
      });

      return NextResponse.json({ error: "Invalid password" }, { status: 401 });
    }

    // Gate: unverified accounts cannot sign in.
    if (!user.email_verified) {
      return NextResponse.json(
        { error: "Please verify your email before signing in.", needsVerification: true },
        { status: 403 },
      );
    }

    // Create session
    const sessionToken = crypto.randomUUID();
    const expires = new Date();
    expires.setDate(expires.getDate() + 30);
    await sql`
      INSERT INTO sessions (session_token, user_id, expires)
      VALUES (${sessionToken}, ${user.id}, ${expires.toISOString()})
    `;

    // Audit log
    await logAudit({
      familyId: user.family_id,
      userId: user.id,
      action: "login",
      request,
    });

    // Get family info
    let family = null;
    if (user.family_id) {
      const families = await sql`
        SELECT id, name, tier, max_children, max_members
        FROM families WHERE id = ${user.family_id}
      `;
      family = families?.[0];
    }

    const response = NextResponse.json({
      success: true,
      userId: user.id,
      email: user.email,
      familyId: user.family_id,
      family,
    });

    response.cookies.set("tia_session", sessionToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === "production",
      sameSite: "lax",
      maxAge: 60 * 60 * 24 * 30,
      path: "/",
    });
    return response;
  } catch (error) {
    console.error("Auth error:", error);
    return NextResponse.json({ error: String(error) }, { status: 500 });
  }
}