import { createDBPool } from "@/internal/datastore/index";
import dotenv from "dotenv";
import fs from "fs/promises";
import path from "path";
import { createHash } from "crypto";

dotenv.config();

const config = {
  host: process.env.DATABASE_HOST,
  port: parseInt(process.env.DATABASE_PORT || "5432"),
  database: process.env.DATABASE_NAME,
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PWD,
  ssl:
    process.env.DATABASE_HOST !== "localhost" &&
    process.env.DATABASE_HOST !== "127.0.0.1"
      ? { rejectUnauthorized: false }
      : undefined,
};

function stringToUUID(str: string): string {
  const hash = createHash("sha256").update(str).digest("hex");
  return [
    hash.substring(0, 8),
    hash.substring(8, 12),
    "4" + hash.substring(13, 16),
    ((parseInt(hash.substring(16, 18), 16) & 0x3f) | 0x80).toString(16) + hash.substring(18, 20),
    hash.substring(20, 32),
  ].join("-");
}

function findResortId(resortNameInJson: string, dbResorts: any[]): string | null {
  const clean = (s: string) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
  const cleanJsonName = clean(resortNameInJson);

  // Exact clean match
  for (const r of dbResorts) {
    if (clean(r.name) === cleanJsonName) {
      return r.id;
    }
  }

  // Substring clean match
  for (const r of dbResorts) {
    if (cleanJsonName.includes(clean(r.name)) || clean(r.name).includes(cleanJsonName)) {
      return r.id;
    }
  }

  return null;
}

async function run() {
  console.log("Starting Hot Deals seeding...");
  const db = createDBPool(config);

  try {
    const jsonPath = path.resolve(process.cwd(), "hot-deals.json");
    console.log(`Reading hot deals from: ${jsonPath}`);
    const jsonRaw = await fs.readFile(jsonPath, "utf-8");
    const hotDeals = JSON.parse(jsonRaw);

    console.log("Fetching resorts from database...");
    const dbResorts = await db.selectFrom("resorts" as any).select(["id", "name", "code"]).execute();
    console.log(`Found ${dbResorts.length} resorts in database.`);

    let successCount = 0;
    let failCount = 0;

    for (const [key, deal] of Object.entries(hotDeals) as [string, any][]) {
      const resortName = deal.resort;
      if (!resortName) {
        console.warn(`[WARNING] Skipping deal "${key}" because resort name is missing.`);
        failCount++;
        continue;
      }

      const resortId = findResortId(resortName, dbResorts);
      if (!resortId) {
        console.warn(`[WARNING] Skipping deal "${key}" because no matching resort was found for "${resortName}".`);
        failCount++;
        continue;
      }

      const parsedId = stringToUUID(key);
      const offerType = deal.type === "exclusive_offer" ? "EXCLUSIVE_DISCOVERY" : "HOT_DEAL";

      // Parse booking period
      const bookingStart = deal.starts ? deal.starts.split(" ")[0] : null;
      const bookingEnd = deal.expires ? deal.expires.split(" ")[0] : null;

      // Parse travel period
      const travelStart = deal.travel_between?.[0]?.[0] || null;
      const travelEnd = deal.travel_between?.[0]?.[1] || null;

      // Parse inclusions and terms
      const inclusions = deal.inclusions || null;
      const terms = deal.terms_conditions || null;

      const offerData = {
        id: parsedId,
        name: deal.master_info?.tagline || key,
        offer_type: offerType,
        description: deal.master_info?.price || null,
        resort_id: resortId,
        is_active: true,
        is_cancellable: false,
        booking_period_start: bookingStart,
        booking_period_end: bookingEnd,
        travel_period_start: travelStart,
        travel_period_end: travelEnd,
        blocked_account_types: [],
        blocked_account_statuses: [],
        blocked_clubs: [],
        allowed_user_types: ["LEGAL_OWNER", "FAMILY_MEMBER"],
        inclusions: inclusions,
        terms_and_conditions: terms,
        confirmation_edm_template_ids: [],
        cancellation_edm_template_ids: [],
        publish_mode: "PUBLISHED",
        published_at: new Date(),
        updated_at: new Date(),
      };

      console.log(`Syncing deal "${key}" -> UUID: ${parsedId} (${resortName})`);

      await db
        .insertInto("member_offers" as any)
        .values(offerData)
        .onConflict((oc) =>
          oc.column("id" as any).doUpdateSet({
            name: offerData.name,
            offer_type: offerData.offer_type,
            description: offerData.description,
            resort_id: offerData.resort_id,
            is_active: offerData.is_active,
            is_cancellable: offerData.is_cancellable,
            booking_period_start: offerData.booking_period_start,
            booking_period_end: offerData.booking_period_end,
            travel_period_start: offerData.travel_period_start,
            travel_period_end: offerData.travel_period_end,
            inclusions: offerData.inclusions,
            terms_and_conditions: offerData.terms_and_conditions,
            publish_mode: offerData.publish_mode,
            published_at: offerData.published_at,
            updated_at: offerData.updated_at,
          }),
        )
        .execute();

      // Clear previous unit connections for this offer
      await db.deleteFrom("member_offer_units" as any).where("member_offer_id", "=", parsedId).execute();

      // Setup units mapping
      if (Array.isArray(deal.unit_code) && deal.unit_code.length > 0) {
        // Fetch resort units
        const dbUnits = await db
          .selectFrom("resort_units" as any)
          .select(["id", "unit_vp_code"])
          .where("resort_id", "=", resortId)
          .execute();

        // Parse values
        let offerValueType = "PERCENTAGE";
        let offerValue = 75;
        const priceStr = deal.master_info?.price || "";
        const pctMatch = priceStr.match(/(\d+)%\s*Off/i);
        if (pctMatch) {
          offerValue = parseInt(pctMatch[1]);
          offerValueType = "PERCENTAGE";
        } else if (typeof deal.price === "number") {
          offerValue = deal.price;
          offerValueType = "POINTS";
        }

        const minNights = deal.phase_3_min_night || deal.night || null;
        const maxNights = deal.phase_3_max_night || deal.night || null;

        const unitOffersToInsert = [];
        for (const code of deal.unit_code) {
          const matchedUnit = dbUnits.find(
            (u: any) => u.unit_vp_code.toLowerCase().trim() === code.toLowerCase().trim(),
          );
          if (matchedUnit) {
            unitOffersToInsert.push({
              member_offer_id: parsedId,
              resort_unit_id: matchedUnit.id,
              is_admin_override: true,
              offer_value_type: offerValueType,
              offer_value: offerValue,
              minimum_nights: minNights,
              maximum_nights_per_booking: maxNights,
              maximum_units_per_membership: 2,
              created_at: new Date(),
              updated_at: new Date(),
            });
          } else {
            console.log(`  [INFO] Unit code "${code}" not found in database for resort "${resortName}".`);
          }
        }

        if (unitOffersToInsert.length > 0) {
          await db.insertInto("member_offer_units" as any).values(unitOffersToInsert).execute();
          console.log(`  Mapped ${unitOffersToInsert.length} units to offer "${key}".`);
        }
      }

      successCount++;
    }

    console.log(`\nSeeding completed: ${successCount} successfully synced, ${failCount} failed.`);
  } catch (err) {
    console.error("Seeding failed with error:", err);
  } finally {
    await db.destroy();
  }
}

run();
