import type { FastifyInstance, FastifyRequest } from "fastify";
import type { MultipartFile } from "@fastify/multipart";
import { z } from "zod";

import { env } from "../config.js";
import { AppError } from "../lib/errors.js";
import { supabaseAdmin } from "../lib/supabase.js";
import { isoNow } from "../lib/utils.js";
import { requireOrganizationMembership } from "../services/auth-service.js";

const MAX_TEST_EMAILS = 100;
const publicApiBaseUrl = (env.API_PUBLIC_BASE_URL || env.APP_BASE_URL).replace(/\/$/, "");

function resolveBrandAssetUrl(request: FastifyRequest, organizationId: string, path?: string | null) {
  if (!path) return null;

  const forwardedProtocol = request.headers["x-forwarded-proto"];
  const forwardedHost = request.headers["x-forwarded-host"];
  const protocol = Array.isArray(forwardedProtocol)
    ? forwardedProtocol[0]
    : String(forwardedProtocol ?? request.protocol ?? "https").split(",")[0]?.trim() || "https";
  const host = Array.isArray(forwardedHost)
    ? forwardedHost[0]
    : Array.isArray(request.headers.host)
      ? request.headers.host[0]
      : forwardedHost ?? request.headers.host;

  if (!host) {
    return `${publicApiBaseUrl}/api/public/brand-kit/logo/${organizationId}`;
  }

  return `${protocol}://${host}/api/public/brand-kit/logo/${organizationId}`;
}

async function toBuffer(file: MultipartFile) {
  const chunks: Buffer[] = [];

  for await (const chunk of file.file) {
    chunks.push(Buffer.from(chunk));
  }

  return Buffer.concat(chunks);
}

function parseTestEmails(rawValue?: string) {
  if (!rawValue) return [];

  try {
    const parsed = JSON.parse(rawValue) as unknown;
    if (!Array.isArray(parsed)) return [];

    const unique = new Set<string>();
    parsed.forEach((value) => {
      const normalized = String(value ?? "").trim().toLowerCase();
      if (!normalized || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/i.test(normalized)) return;
      unique.add(normalized);
    });

    return Array.from(unique).slice(0, MAX_TEST_EMAILS);
  } catch {
    return [];
  }
}

export function registerBrandKitRoutes(app: FastifyInstance) {
  app.get("/api/public/brand-kit/logo/:organizationId", async (request, reply) => {
    const params = z.object({ organizationId: z.string().uuid() }).parse(request.params);

    const { data, error } = await supabaseAdmin
      .from("brand_kits")
      .select("logo_path")
      .eq("organization_id", params.organizationId)
      .maybeSingle();

    if (error) {
      throw new AppError(400, "BRAND_KIT_LOOKUP_FAILED", error.message);
    }

    if (!data?.logo_path) {
      reply.code(404);
      return { error: "Logo not found." };
    }

    const download = await supabaseAdmin.storage.from("brand-assets").download(String(data.logo_path));

    if (download.error || !download.data) {
      throw new AppError(404, "BRAND_LOGO_NOT_FOUND", download.error?.message ?? "Logo not found.");
    }

    const buffer = Buffer.from(await download.data.arrayBuffer());
    if (download.data.type) {
      reply.header("Content-Type", download.data.type);
    }
    reply.header("Cache-Control", "public, max-age=3600");
    return reply.send(buffer);
  });

  app.get("/api/brand-kit/:organizationId", async (request) => {
    const params = z.object({ organizationId: z.string().uuid() }).parse(request.params);
    await requireOrganizationMembership(request, params.organizationId);

    const [{ data, error }, { data: organization, error: organizationError }] = await Promise.all([
      supabaseAdmin
        .from("brand_kits")
        .select("*")
        .eq("organization_id", params.organizationId)
        .maybeSingle(),
      supabaseAdmin
        .from("organizations")
        .select("name, website_url")
        .eq("id", params.organizationId)
        .maybeSingle()
    ]);

    if (error) {
      throw new AppError(400, "BRAND_KIT_LOOKUP_FAILED", error.message);
    }

    if (organizationError) {
      throw new AppError(400, "BRAND_KIT_LOOKUP_FAILED", organizationError.message);
    }

    const logoUrl = resolveBrandAssetUrl(request, params.organizationId, data?.logo_path);

    return {
        brandKit: {
        brand_name: organization?.name ?? "Organization",
        website_url: organization?.website_url ?? "",
        primary_color: data?.primary_color ?? "#0f766e",
        secondary_color: data?.secondary_color ?? "#0f172a",
        accent_color: data?.accent_color ?? "#14b8a6",
        test_emails: Array.isArray(data?.test_emails) ? data.test_emails : [],
        logo_path: data?.logo_path ?? null,
        logo_url: logoUrl
      }
    };
  });

  app.put("/api/brand-kit/:organizationId", async (request) => {
    const params = z.object({ organizationId: z.string().uuid() }).parse(request.params);
    await requireOrganizationMembership(request, params.organizationId);

    const { data: existingBrandKit, error: existingBrandKitError } = await supabaseAdmin
      .from("brand_kits")
      .select("logo_path")
      .eq("organization_id", params.organizationId)
      .maybeSingle();

    if (existingBrandKitError) {
      throw new AppError(400, "BRAND_KIT_LOOKUP_FAILED", existingBrandKitError.message);
    }

    const parts = request.parts();
    const payload: Record<string, string> = {};
    let uploadedPath: string | null = null;

    for await (const part of parts) {
      if (part.type === "file") {
        const buffer = await toBuffer(part);
        uploadedPath = `orgs/${params.organizationId}/brand/${Date.now()}-${part.filename}`;
        const upload = await supabaseAdmin.storage.from("brand-assets").upload(uploadedPath, buffer, {
          contentType: part.mimetype,
          upsert: true
        });

        if (upload.error) {
          throw new AppError(400, "BRAND_ASSET_UPLOAD_FAILED", upload.error.message);
        }
      } else {
        payload[part.fieldname] = String(part.value ?? "");
      }
    }

    if (payload.brandName?.trim()) {
      const { error: organizationError } = await supabaseAdmin
        .from("organizations")
        .update({
          name: payload.brandName.trim(),
          website_url: payload.websiteUrl?.trim() || null,
          updated_at: isoNow()
        })
        .eq("id", params.organizationId);

      if (organizationError) {
        throw new AppError(400, "BRAND_NAME_UPDATE_FAILED", organizationError.message);
      }
    }

    if (!payload.brandName?.trim() && typeof payload.websiteUrl === "string") {
      const { error: websiteError } = await supabaseAdmin
        .from("organizations")
        .update({
          website_url: payload.websiteUrl.trim() || null,
          updated_at: isoNow()
        })
        .eq("id", params.organizationId);

      if (websiteError) {
        throw new AppError(400, "BRAND_WEBSITE_UPDATE_FAILED", websiteError.message);
      }
    }

    const record = {
      organization_id: params.organizationId,
      logo_path: uploadedPath ?? payload.logoPath ?? existingBrandKit?.logo_path ?? null,
      primary_color: payload.primaryColor ?? "#0f766e",
      secondary_color: payload.secondaryColor ?? "#0f172a",
      accent_color: payload.accentColor ?? "#14b8a6",
      test_emails: parseTestEmails(payload.testEmails),
      updated_at: isoNow()
    };

    let result = await supabaseAdmin
      .from("brand_kits")
      .upsert(record, {
        onConflict: "organization_id"
      })
      .select("*")
      .single();

    if (result.error && /test_emails/i.test(result.error.message)) {
      const { test_emails: _ignored, ...legacyRecord } = record;
      result = await supabaseAdmin
        .from("brand_kits")
        .upsert(legacyRecord, {
          onConflict: "organization_id"
        })
        .select("*")
        .single();
    }

    const { data, error } = result;

    if (error) {
      throw new AppError(400, "BRAND_KIT_UPDATE_FAILED", error.message);
    }

    const logoUrl = resolveBrandAssetUrl(request, params.organizationId, data.logo_path);

  const { data: organization, error: organizationError } = await supabaseAdmin
      .from("organizations")
      .select("name, website_url")
      .eq("id", params.organizationId)
      .maybeSingle();

    if (organizationError) {
      throw new AppError(400, "BRAND_KIT_UPDATE_FAILED", organizationError.message);
    }

    return {
      brandKit: {
        ...data,
        brand_name: organization?.name ?? payload.brandName ?? "Organization",
        website_url: organization?.website_url ?? payload.websiteUrl ?? "",
        test_emails: Array.isArray(data?.test_emails) ? data.test_emails : parseTestEmails(payload.testEmails),
        logo_url: logoUrl
      }
    };
  });
}
