import type { FastifyPluginAsync } from "fastify";
import { z } from "zod";
import { requireAuth, requireRestaurantMember } from "../lib/auth.js";
import { slugify } from "@menulio/shared";
import { generateUniqueRestaurantSlug } from "../lib/slug.js";
import { supabase } from "../lib/supabase.js";
import { deleteCustomHostname, getCustomHostnameByHostname } from "../lib/cloudflare.js";

const createRestaurantSchema = z.object({
  name: z.string().min(1).max(120),
  logoUrl: z.string().nullish(),
  phone: z.string().max(30).nullish(),
  address: z.string().max(500).nullish(),
});

const updateRestaurantSchema = z.object({
  name: z.string().min(1).max(120).optional(),
  logoUrl: z.string().nullish(),
  phone: z.string().max(30).nullish(),
  address: z.string().max(500).nullish(),
  slug: z.string().min(2).max(100).optional(),
});

export const restaurantsRoutes: FastifyPluginAsync = async (app) => {
  app.post("/restaurants", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

    const parsed = createRestaurantSchema.safeParse(req.body);
    if (!parsed.success) {
      return reply.code(400).send({ message: "invalid body", issues: parsed.error.issues });
    }

    const { name, logoUrl, phone, address } = parsed.data;
    const slug = await generateUniqueRestaurantSlug(name);

    const { data: restaurant, error: restaurantError } = await supabase
      .from("restaurants")
      .insert({
        name,
        slug,
        logo_url: logoUrl ?? null,
        phone: phone ?? null,
        address: address ?? null,
        created_by: userId,
      })
      .select()
      .single();

    if (restaurantError || !restaurant) {
      req.log.error(restaurantError);
      return reply.code(500).send({ message: "failed to create restaurant" });
    }

    const { error: memberError } = await supabase
      .from("restaurant_members")
      .insert({ restaurant_id: restaurant.id, user_id: userId, role: "owner" });

    const { data: location, error: locationError } = await supabase
      .from("locations")
      .insert({ restaurant_id: restaurant.id, name: "Ana Şube" })
      .select()
      .single();

    if (memberError || locationError || !location) {
      req.log.error(memberError ?? locationError);
      return reply.code(500).send({ message: "failed to finish restaurant setup" });
    }

    const { data: menu, error: menuError } = await supabase
      .from("menus")
      .insert({ location_id: location.id, name: "Menüm" })
      .select()
      .single();

    if (menuError || !menu) {
      req.log.error(menuError);
      return reply.code(500).send({ message: "failed to create default menu" });
    }

    return reply.code(201).send({ restaurant, location, menu });
  });

  app.get("/restaurants/:id", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

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

    const { data, error } = await supabase.from("restaurants").select().eq("id", id).single();
    if (error || !data) return reply.code(404).send({ message: "not found" });

    return reply.send(data);
  });

  app.patch("/restaurants/:id", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

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

    const parsed = updateRestaurantSchema.safeParse(req.body);
    if (!parsed.success) {
      return reply.code(400).send({ message: "invalid body", issues: parsed.error.issues });
    }

    const { name, logoUrl, phone, address, slug } = parsed.data;

    let formattedSlug: string | undefined = undefined;
    if (slug !== undefined) {
      const cleanSlug = slugify(slug);
      if (!cleanSlug || cleanSlug.length < 2) {
        return reply.code(400).send({ message: "Geçersiz menü adresi formatı. Harf ve rakamlardan oluşmalıdır." });
      }

      const RESERVED_SLUGS = new Set([
        "demo", "templates", "admin", "api", "privacy", "support",
        "login", "register", "app", "www", "auth", "account", "menu", "menus", "qr", "settings"
      ]);

      if (RESERVED_SLUGS.has(cleanSlug)) {
        return reply.code(400).send({ message: "Bu menü adresi sistem tarafından ayrılmıştır, kullanılamaz." });
      }

      const { data: existing } = await supabase
        .from("restaurants")
        .select("id")
        .eq("slug", cleanSlug)
        .neq("id", id)
        .maybeSingle();

      if (existing) {
        return reply.code(409).send({ message: "Bu özel menü adresi başka bir restoran tarafından kullanılıyor." });
      }

      formattedSlug = cleanSlug;
    }

    const { data, error } = await supabase
      .from("restaurants")
      .update({
        ...(name !== undefined ? { name } : {}),
        ...(logoUrl !== undefined ? { logo_url: logoUrl } : {}),
        ...(phone !== undefined ? { phone } : {}),
        ...(address !== undefined ? { address } : {}),
        ...(formattedSlug !== undefined ? { slug: formattedSlug } : {}),
        updated_at: new Date().toISOString(),
      })
      .eq("id", id)
      .select()
      .single();

    if (error || !data) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to update restaurant" });
    }

    return reply.send(data);
  });

  app.get("/restaurants/:id/theme", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

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

    const { data: themeRow } = await supabase
      .from("restaurant_themes")
      .select("theme_id, overrides, themes(key, name, config)")
      .eq("restaurant_id", id)
      .maybeSingle();

    return reply.send({
      themeKey: (themeRow?.themes as unknown as { key?: string } | null)?.key ?? "elegant",
      overrides: themeRow?.overrides ?? {},
    });
  });

  app.put("/restaurants/:id/theme", async (req, reply) => {
    const userId = await requireAuth(req, reply);
    if (!userId || !supabase) return;

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

    const { themeKey } = (req.body as { themeKey?: string }) ?? {};
    if (!themeKey) {
      return reply.code(400).send({ message: "themeKey is required" });
    }

    const THEME_NAMES: Record<string, string> = {
      coastal: "Eleia Coastal Kitchen",
      neon: "Neon Street Fuze",
      maison: "La Maison d'Élève",
      swiss: "Swiss Brutalist",
      artisan: "Amber Artisan",
      elegant: "Elegant Gold",
      modern: "Modern Sapphire",
      dark: "Luxury Dark",
      minimal: "Nordic Minimal",
      classic: "Classic Bistro",
    };

    const { data: themeData } = await supabase.from("themes").select("id").eq("key", themeKey).maybeSingle();

    let themeId = themeData?.id;
    if (!themeId) {
      const { data: newTheme } = await supabase
        .from("themes")
        .insert({
          key: themeKey,
          name: THEME_NAMES[themeKey] || themeKey,
          config: { primaryColor: themeKey === "swiss" ? "#000000" : "#E5A855", background: themeKey === "swiss" ? "#FFFFFF" : "#121316", productLayout: "card", categoryLayout: "tabs" },
        })
        .select("id")
        .maybeSingle();

      if (newTheme?.id) {
        themeId = newTheme.id;
      }
    }

    if (!themeId) {
      return reply.code(404).send({ message: "Theme not found" });
    }

    const { error } = await supabase.from("restaurant_themes").upsert(
      {
        restaurant_id: id,
        theme_id: themeId,
      },
      { onConflict: "restaurant_id" },
    );

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

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

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

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

    // Delete custom hostnames from Cloudflare if any custom domains exist
    const { data: domains } = await supabase.from("domains").select("id, hostname").eq("restaurant_id", id);
    if (domains && domains.length > 0) {
      for (const dom of domains) {
        try {
          const cfHostname = await getCustomHostnameByHostname(dom.hostname);
          if (cfHostname?.id) {
            await deleteCustomHostname(cfHostname.id);
          }
        } catch (err) {
          req.log.warn({ err, hostname: dom.hostname }, "Cloudflare hostname delete failed during restaurant deletion");
        }
      }
    }

    // Delete associated database records
    await supabase.from("domains").delete().eq("restaurant_id", id);
    await supabase.from("restaurant_themes").delete().eq("restaurant_id", id);
    await supabase.from("restaurant_members").delete().eq("restaurant_id", id);

    // Delete locations, menus, categories, items
    const { data: locations } = await supabase.from("locations").select("id").eq("restaurant_id", id);
    if (locations && locations.length > 0) {
      const locIds = locations.map((l) => l.id);
      const { data: menus } = await supabase.from("menus").select("id").in("location_id", locIds);
      if (menus && menus.length > 0) {
        const menuIds = menus.map((m) => m.id);
        const { data: categories } = await supabase.from("menu_categories").select("id").in("menu_id", menuIds);
        if (categories && categories.length > 0) {
          const catIds = categories.map((c) => c.id);
          await supabase.from("menu_items").delete().in("category_id", catIds);
          await supabase.from("menu_categories").delete().in("menu_id", menuIds);
        }
        await supabase.from("menus").delete().in("location_id", locIds);
      }
      await supabase.from("locations").delete().eq("restaurant_id", id);
    }

    const { error } = await supabase.from("restaurants").delete().eq("id", id);
    if (error) {
      req.log.error(error);
      return reply.code(500).send({ message: "failed to delete restaurant" });
    }

    return reply.send({ success: true, message: "Restoran başarıyla silindi." });
  });
};
