import type { FastifyPluginAsync } from "fastify";
import { z } from "zod";
import { requireAuth, requireRestaurantMember } from "../lib/auth.js";
import { env } from "../env.js";
import { supabase } from "../lib/supabase.js";
import { addDomainToWebApp } from "../lib/coolify.js";
import { createCustomHostname, getCustomHostnameByHostname } from "../lib/cloudflare.js";

const addDomainSchema = z.object({
  hostname: z
    .string()
    .min(3)
    .max(255)
    .transform((val) => val.toLowerCase().trim().replace(/^https?:\/\//, "").replace(/\/.*$/, "")),
});

export const domainsRoutes: FastifyPluginAsync = async (app) => {
  // Get all domains for a restaurant
  app.get("/restaurants/:id/domains", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

    const { id: restaurantId } = req.params as { id: string };
    const isMember = await requireRestaurantMember(userId, restaurantId);
    if (!isMember) return reply.code(403).send({ message: "forbidden" });

    const { data: domains, error } = await supabase
      .from("domains")
      .select()
      .eq("restaurant_id", restaurantId)
      .order("created_at", { ascending: false });

    if (error) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to load domains" });
    }

    const cnameTarget = `cname.${env.ROOT_DOMAIN}`;

    const enrichedDomains = await Promise.all(
      (domains || []).map(async (domain) => {
        if (domain.status === "verified") return domain;

        try {
          const cfHostname = await getCustomHostnameByHostname(domain.hostname);
          if (cfHostname) {
            const ownershipTxt = cfHostname.ownership_verification
              ? { name: cfHostname.ownership_verification.name, value: cfHostname.ownership_verification.value }
              : null;
            const sslTxt = (cfHostname.ssl?.validation_records ?? []).map((r) => ({
              name: r.txt_name,
              value: r.txt_value,
            }));

            return {
              ...domain,
              instructions: {
                cname: { type: "CNAME", host: domain.hostname, target: cnameTarget },
                ownershipTxt,
                sslTxt,
              },
              cloudflareStatus: {
                hostnameStatus: cfHostname.status,
                sslStatus: cfHostname.ssl?.status,
                ownershipTxt,
                sslTxt,
              },
            };
          }
        } catch (err) {
          req.log.warn({ err, hostname: domain.hostname }, "Cloudflare check failed during GET domains");
        }

        return domain;
      }),
    );

    return reply.send({
      domains: enrichedDomains,
      cnameTarget,
      instructions: {
        type: "CNAME",
        target: cnameTarget,
      },
    });
  });

  // Add a custom domain — registers it with Cloudflare (SSL for SaaS) and
  // the origin (Coolify) so it's routable/certifiable, not just recorded.
  app.post("/restaurants/:id/domains", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

    const { id: restaurantId } = req.params as { id: string };
    const isMember = await requireRestaurantMember(userId, restaurantId);
    if (!isMember) return reply.code(403).send({ message: "forbidden" });

    const parsed = addDomainSchema.safeParse(req.body);
    if (!parsed.success) {
      return reply.code(400).send({ message: "Geçersiz alan adı formatı", issues: parsed.error.issues });
    }

    const { hostname } = parsed.data;

    const { data: existing } = await supabase
      .from("domains")
      .select("id, restaurant_id")
      .eq("hostname", hostname)
      .maybeSingle();

    if (existing) {
      if (existing.restaurant_id === restaurantId) {
        return reply.code(409).send({ message: "Bu alan adı zaten bu restorana eklenmiş." });
      }
      return reply.code(409).send({ message: "Bu alan adı başka bir hesap tarafından kullanılıyor." });
    }

    const { data: newDomain, error } = await supabase
      .from("domains")
      .insert({
        restaurant_id: restaurantId,
        hostname,
        is_custom: true,
        status: "pending",
      })
      .select()
      .single();

    if (error || !newDomain) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to add domain" });
    }

    const cnameTarget = `cname.${env.ROOT_DOMAIN}`;
    const warnings: string[] = [];
    let dcvTxt: { name: string; value: string } | null = null;
    let sslTxt: { name: string; value: string }[] = [];

    try {
      const hostnameRecord = await createCustomHostname(hostname);
      if (hostnameRecord.ownership_verification) {
        dcvTxt = { name: hostnameRecord.ownership_verification.name, value: hostnameRecord.ownership_verification.value };
      }
      sslTxt = (hostnameRecord.ssl.validation_records ?? []).map((r) => ({ name: r.txt_name, value: r.txt_value }));
    } catch (err) {
      req.log.warn({ err, hostname }, "Cloudflare custom hostname creation failed");
      warnings.push("Cloudflare kaydı oluşturulamadı, manuel kurulum gerekebilir.");
    }

    try {
      await addDomainToWebApp(hostname);
    } catch (err) {
      req.log.warn({ err, hostname }, "Coolify domain add failed");
      warnings.push("Sunucu routing'i otomatik eklenemedi, manuel kurulum gerekebilir.");
    }

    return reply.status(201).send({
      domain: newDomain,
      cnameTarget,
      instructions: {
        cname: { type: "CNAME", host: hostname, target: cnameTarget },
        ownershipTxt: dcvTxt,
        sslTxt,
      },
      warnings,
    });
  });

  // Verification checks Cloudflare's own Custom Hostname SSL status — a
  // plain DNS lookup can't see a proxied domain's real CNAME target, so
  // that approach always failed for hostnames set up correctly (see
  // docs/PROGRESS.md, 2026-08-20).
  app.post("/restaurants/:id/domains/:domainId/verify", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

    const { id: restaurantId, domainId } = req.params as { id: string; domainId: string };
    const isMember = await requireRestaurantMember(userId, restaurantId);
    if (!isMember) return reply.code(403).send({ message: "forbidden" });

    const { data: domain, error: domainError } = await supabase
      .from("domains")
      .select()
      .eq("id", domainId)
      .eq("restaurant_id", restaurantId)
      .single();

    if (domainError || !domain) {
      return reply.code(404).send({ message: "domain not found" });
    }

    let cfHostname: Awaited<ReturnType<typeof getCustomHostnameByHostname>> = null;
    try {
      cfHostname = await getCustomHostnameByHostname(domain.hostname);
    } catch (err) {
      req.log.warn({ err, hostname: domain.hostname }, "Cloudflare status check failed");
    }

    const isVerified = cfHostname?.status === "active" && cfHostname?.ssl?.status === "active";

    if (isVerified) {
      const { data: updated } = await supabase
        .from("domains")
        .update({ status: "verified", verified_at: new Date().toISOString() })
        .eq("id", domainId)
        .select()
        .single();

      return reply.send({
        verified: true,
        domain: updated,
        message: `Tebrikler! ${domain.hostname} alan adı doğrulandı ve menünüze bağlandı. 🎉`,
      });
    }

    // Never downgrade an already-verified domain on an inconclusive re-check.
    if (domain.status !== "verified") {
      await supabase.from("domains").update({ status: "pending", verified_at: null }).eq("id", domainId);
    }

    return reply.send({
      verified: domain.status === "verified",
      domain: domain.status === "verified" ? domain : { ...domain, status: "pending", verified_at: null },
      cloudflareStatus: cfHostname
        ? {
            hostnameStatus: cfHostname.status,
            sslStatus: cfHostname.ssl?.status,
            ownershipTxt: cfHostname.ownership_verification
              ? { name: cfHostname.ownership_verification.name, value: cfHostname.ownership_verification.value }
              : null,
            sslTxt: (cfHostname.ssl?.validation_records ?? []).map((r) => ({ name: r.txt_name, value: r.txt_value })),
          }
        : null,
      message: cfHostname
        ? `Henüz aktif değil (hostname: ${cfHostname.status}, sertifika: ${cfHostname.ssl?.status}). DNS kayıtlarının işlenmesi birkaç dakika sürebilir.`
        : `${domain.hostname} Cloudflare'de bulunamadı. Domain eklerken bir hata oluşmuş olabilir, tekrar eklemeyi deneyin.`,
    });
  });

  // Delete custom domain
  app.delete("/restaurants/:id/domains/:domainId", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

    const { id: restaurantId, domainId } = req.params as { id: string; domainId: string };
    const isMember = await requireRestaurantMember(userId, restaurantId);
    if (!isMember) return reply.code(403).send({ message: "forbidden" });

    const { error } = await supabase
      .from("domains")
      .delete()
      .eq("id", domainId)
      .eq("restaurant_id", restaurantId);

    if (error) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to delete domain" });
    }

    return reply.send({ success: true });
  });
};
