import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { getCurrentUser } from "@/lib/auth";
import { createTrackedSite } from "@/lib/services/site-tag";
import { ensureSubscription } from "@/lib/services/billing";
import { log } from "@/lib/logger";
import { sanitizeBrandArray, deriveLegacyLocation, deriveLegacyServiceType } from "@/lib/brand-helpers";

/**
 * POST /api/onboarding
 *
 * Creates everything needed for a new brand in one call:
 * 1. Organization (if user doesn't have one yet)
 * 2. Brand
 * 3. Website
 * 4. Brand Profile (intake data)
 * 5. Empty Dashboard Data (placeholder)
 *
 * Body:
 * {
 *   orgName?: string,          // optional — skipped if user already has an org
 *   brandName: string,         // required
 *   domain: string,            // required
 *   industry?: string,
 *   serviceType?: string,      // legacy single-string — kept for backwards compat
 *   location?: string,         // legacy single-string — kept for backwards compat
 *   locations?: string[],            // multi-location, free-text chips
 *   primaryServices?: string[],      // main service offerings (chips)
 *   secondaryServices?: string[],    // supporting service offerings (chips)
 *   businessType?: string,
 *   services?: string[],             // BrandProfile-only legacy field
 *   brandColors?: string[],
 *   targetAudience?: string,
 *   description?: string,
 * }
 *
 * Array fields (locations / primaryServices / secondaryServices) are
 * sanitized via sanitizeBrandArray (trim, drop empties, dedupe,
 * 20-entry / 200-char caps). When non-empty they win over the legacy
 * single-string fields. The legacy fields are written alongside —
 * `location = locations[0]` and `serviceType = primaryServices.join(", ")` —
 * so consumers that haven't migrated to the array helpers keep
 * working.
 */
export const dynamic = "force-dynamic";

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

  try {
    const body = await req.json();
    const { brandName, domain } = body;

    if (!brandName?.trim() || !domain?.trim()) {
      return NextResponse.json({ error: "brandName and domain are required" }, { status: 400 });
    }

    // Sanitize the new array fields up-front so a bad payload fails
    // fast with a structured error instead of slipping through to a
    // Prisma validation error mid-transaction.
    const locationsCheck = sanitizeBrandArray(body.locations, "locations");
    if (!locationsCheck.ok) return NextResponse.json({ error: locationsCheck.error }, { status: 400 });
    const primaryCheck = sanitizeBrandArray(body.primaryServices, "primaryServices");
    if (!primaryCheck.ok) return NextResponse.json({ error: primaryCheck.error }, { status: 400 });
    const secondaryCheck = sanitizeBrandArray(body.secondaryServices, "secondaryServices");
    if (!secondaryCheck.ok) return NextResponse.json({ error: secondaryCheck.error }, { status: 400 });

    // Derive final values: arrays win when provided, otherwise fall
    // back to legacy single-string body fields (so legacy intake
    // clients sending only `location` / `serviceType` still work).
    const finalLocations = locationsCheck.value.length > 0
      ? locationsCheck.value
      : (body.location && typeof body.location === "string" && body.location.trim()
          ? [body.location.trim()]
          : []);
    const finalPrimary = primaryCheck.value.length > 0
      ? primaryCheck.value
      : (body.serviceType && typeof body.serviceType === "string" && body.serviceType.trim()
          ? [body.serviceType.split(",")[0].trim()].filter(Boolean)
          : []);
    const finalSecondary = secondaryCheck.value.length > 0
      ? secondaryCheck.value
      : (body.serviceType && typeof body.serviceType === "string" && body.serviceType.includes(",")
          ? body.serviceType.split(",").slice(1).map((s: string) => s.trim()).filter(Boolean)
          : []);
    const legacyLocation = deriveLegacyLocation(finalLocations, body.location);
    const legacyServiceType = deriveLegacyServiceType(finalPrimary, body.serviceType);

    // Step 1: Find or create organization
    let org = user.memberships[0]?.organization ?? null;

    if (!org) {
      const orgName = body.orgName?.trim() || `${user.name || "My"}'s Workspace`;
      const slug = orgName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");

      org = await prisma.organization.create({
        data: {
          name: orgName,
          slug: slug + "-" + Date.now().toString(36),
          memberships: {
            create: { userId: user.id, role: "owner" },
          },
        },
      });
    }

    // Step 2: Generate initials
    const words = brandName.trim().split(/\s+/);
    const initials = words.length >= 2
      ? (words[0][0] + words[1][0]).toUpperCase()
      : brandName.trim().substring(0, 2).toUpperCase();

    // Step 3: Clean domain
    const cleanDomain = domain.trim().replace(/^https?:\/\//, "").replace(/\/+$/, "");

    // Step 4: Create brand + website + profile + dashboard in one transaction
    const brand = await prisma.brand.create({
      data: {
        name: brandName.trim(),
        domain: cleanDomain,
        industry: body.industry || null,
        // Legacy single-string fields synced from the array values
        // above so consumers that haven't migrated keep working.
        serviceType: legacyServiceType,
        location: legacyLocation,
        // Array source-of-truth for multi-location / categorized
        // service support. Empty arrays are valid — the brand will
        // surface as "calibrating" until the user fills these in
        // via the Edit Brand page.
        locations: finalLocations,
        primaryServices: finalPrimary,
        secondaryServices: finalSecondary,
        initials,
        orgId: org.id,

        websites: {
          create: {
            url: `https://${cleanDomain}`,
            isPrimary: true,
          },
        },

        profile: {
          create: {
            companyName: brandName.trim(),
            businessType: body.businessType || null,
            // BrandProfile.services / .locations are pre-existing
            // intake fields. Mirror the new Brand-level arrays here
            // when they're set so the BrandProfile stays consistent
            // with the Brand record without duplicating the field
            // taxonomy. Falls back to legacy body shape if arrays
            // weren't supplied.
            services: finalPrimary.length > 0 || finalSecondary.length > 0
              ? [...finalPrimary, ...finalSecondary]
              : (body.services || []),
            locations: finalLocations.length > 0
              ? finalLocations
              : (body.locations || (body.location ? [body.location] : [])),
            brandColors: body.brandColors || [],
            targetAudience: body.targetAudience || null,
            description: body.description || null,
          },
        },

        dashboardData: {
          create: {
            seoScore: 0,
            aiVisibility: 0,
            crawlHealth: 0,
            monthlyTraffic: 0,
            revenue: 0,
            revenueChange: 0,
            alertCount: 0,
          },
        },
      },
      include: {
        websites: true,
        profile: true,
        dashboardData: true,
      },
    });

    // Step 5: Auto-create Site Tag for the new brand
    let siteTag = null;
    try {
      const tagResult = await createTrackedSite(org.id, brand.id, cleanDomain);
      siteTag = { siteId: tagResult.siteId, snippet: tagResult.snippet };
    } catch {
      // Site tag creation is optional — don't block onboarding
    }

    // Step 6: Ensure the org has a billing subscription (free trial)
    try {
      await ensureSubscription(org.id);
    } catch {
      // Billing setup is optional — don't block onboarding
    }

    log.info("api", `Onboarding completed: ${brandName} (${cleanDomain})`, {
      path: "/api/onboarding",
      userId: user.id,
      metadata: { orgId: org.id, brandId: brand.id, hasSiteTag: !!siteTag },
    });

    return NextResponse.json({
      organization: { id: org.id, name: org.name, slug: org.slug },
      brand,
      siteTag,
    }, { status: 201 });

  } catch (e) {
    const msg = e instanceof Error ? e.message : "Something went wrong";
    log.error("api", `Onboarding error: ${msg}`, {
      path: "/api/onboarding",
      userId: user.id,
      metadata: { error: msg },
    });
    return NextResponse.json({ error: msg }, { status: 500 });
  }
}
