import { PrismaClient } from "@prisma/client";
import { HOME_FILTER_AMENITIES } from "../src/data/home-filter-amenities";
import { ACCOMMODATION_TYPES_SEED } from "../src/lib/accommodation-types";
import { LOCATION_SEED } from "../src/data/location-seed";

const prisma = new PrismaClient();

/** Slug prefix pentru listări generate — la re-rulare seed se șterg și se recreează. */
const SEED_SLUG_PREFIX = "seed-";

const SEED_TAGS = [
  { name: "Romantic", nameEn: "Romantic", slug: "romantic", icon: "heart" },
  { name: "Familie", nameEn: "Family", slug: "family", icon: "family" },
  { name: "Aventură", nameEn: "Adventure", slug: "aventura", icon: "fire" },
  { name: "Cabana", nameEn: "Cabin", slug: "cabana", icon: "cabin" },
  { name: "Relaxare", nameEn: "Relaxation", slug: "relaxare", icon: "tag" },
  { name: "Natură", nameEn: "Nature", slug: "natura", icon: "tag" },
] as const;

const ADJECTIVES = [
  "Căsuță",
  "Apartament",
  "Cabana",
  "Vila",
  "Studio",
  "Conac",
  "Pensiune",
  "Casă de oaspeți",
  "Loft",
  "Chalet",
];

const PLACES = [
  "la munte",
  "cu vedere",
  "în deal",
  "la poale",
  "central",
  "lângă pădure",
  "la țară",
  "la lac",
  "Cuib",
  "Refugiu",
];

function parseBoolEnv(key: string, defaultValue: boolean): boolean {
  const v = process.env[key]?.trim().toLowerCase();
  if (v == null || v === "") return defaultValue;
  if (["1", "true", "yes", "y", "on"].includes(v)) return true;
  if (["0", "false", "no", "n", "off"].includes(v)) return false;
  return defaultValue;
}

function parseIntEnv(key: string, defaultValue: number, min: number, max: number): number {
  const raw = process.env[key]?.trim();
  if (!raw) return defaultValue;
  const n = Number.parseInt(raw, 10);
  if (!Number.isFinite(n)) return defaultValue;
  return Math.max(min, Math.min(max, n));
}

function rand01(seed: number): number {
  // xorshift32
  let x = seed | 0;
  x ^= x << 13;
  x ^= x >>> 17;
  x ^= x << 5;
  // [0,1)
  return ((x >>> 0) % 1_000_000) / 1_000_000;
}

function pickWeighted<T>(seed: number, items: Array<{ w: number; v: T }>): T {
  const total = items.reduce((a, b) => a + b.w, 0);
  const r = rand01(seed) * total;
  let acc = 0;
  for (const it of items) {
    acc += it.w;
    if (r <= acc) return it.v;
  }
  return items[items.length - 1]!.v;
}

function seededListingName(i: number): string {
  const adj = ADJECTIVES[i % ADJECTIVES.length];
  const place = PLACES[Math.floor(i / ADJECTIVES.length) % PLACES.length];
  return `${adj} ${place} #${i}`;
}

/** Tip cazare pentru listările de test — mereu slug valid pentru `Listing.accommodationType`. */
function accommodationTypeForSeedIndex(i: number): string {
  const name = seededListingName(i);
  const lower = name.toLowerCase();
  if (lower.includes("apartament")) return "apartamente";
  if (lower.includes("căsuță")) return "casute-in-copac";
  if (lower.includes("cabana")) return "cabane";
  if (lower.includes("pensiune")) return "pensiuni";
  if (lower.includes("vila") || lower.includes("conac")) return "vile-case";
  if (lower.includes("studio") || lower.includes("loft")) return "apartamente";
  if (lower.includes("chalet")) return "cabane";
  if (lower.includes("casă de oaspeți")) return "pensiuni";
  return ACCOMMODATION_TYPES_SEED[(i - 1) % ACCOMMODATION_TYPES_SEED.length];
}

function parseSeedCount(): number {
  const raw = process.env.SEED_LISTING_COUNT?.trim();
  if (!raw) return 500;
  const n = Number.parseInt(raw, 10);
  if (!Number.isFinite(n) || n < 0) return 500;
  return Math.min(5000, n);
}

async function seedTestListings() {
  const count = parseSeedCount();
  if (count === 0) {
    console.log("Seed: listări de test oprite (SEED_LISTING_COUNT=0).");
    return;
  }

  const cities: Array<{ id: string }> = await prisma.locationCity.findMany({ select: { id: true } });
  if (cities.length === 0) {
    console.warn("Seed: nu există orașe în DB — sar generarea de listări de test.");
    return;
  }

  const amenityRows: Array<{ id: string }> = await prisma.amenity.findMany({ select: { id: true } });
  const tagRows: Array<{ id: string; slug: string }> = await prisma.tag.findMany({ select: { id: true, slug: true } });
  const tagIds = tagRows.map((t) => t.id);
  const amenityIds = amenityRows.map((a) => a.id);

  const deleted = await prisma.listing.deleteMany({
    where: { slug: { startsWith: SEED_SLUG_PREFIX } },
  });
  if (deleted.count > 0) {
    console.log(`Seed: eliminate ${deleted.count} listări vechi (${SEED_SLUG_PREFIX}*).`);
  }

  const cityIds = cities.map((c) => c.id);
  const listingsPayload = Array.from({ length: count }, (_, idx) => {
    const i = idx + 1;
    const slug = `${SEED_SLUG_PREFIX}${String(i).padStart(4, "0")}`;
    const cityId = cityIds[(i * 7919 + 42) % cityIds.length];
    const priceNight = 120 + ((i * 97) % 980);
    const maxGuests = 2 + (i % 11);
    const name = seededListingName(i);
    const coverSeed = `inv-${slug}`;
    return {
      slug,
      name,
      location: null as string | null,
      priceNight,
      currency: "RON",
      description: `Descriere de test (#${i}). Cazare fictivă pentru testare UI și performanță. Rezervarea se face direct cu proprietarul; acest text nu reprezintă o ofertă reală.`,
      whatsapp: null as string | null,
      websiteUrl: null as string | null,
      coverImageUrl: `https://picsum.photos/seed/${coverSeed}/1200/800`,
      maxGuests,
      cityId,
      accommodationType: accommodationTypeForSeedIndex(i),
    };
  });

  const chunk = 100;
  for (let i = 0; i < listingsPayload.length; i += chunk) {
    await prisma.listing.createMany({ data: listingsPayload.slice(i, i + chunk) });
  }

  const created = await prisma.listing.findMany({
    where: { slug: { startsWith: SEED_SLUG_PREFIX } },
    select: { id: true, slug: true },
    orderBy: { slug: "asc" },
  });

  const images: { listingId: string; url: string; alt: string | null; sortOrder: number }[] = [];
  const listingTags: { listingId: string; tagId: string }[] = [];
  const listingAmenities: { listingId: string; amenityId: string }[] = [];

  for (const row of created) {
    const n = Number.parseInt(row.slug.slice(SEED_SLUG_PREFIX.length), 10) || 0;
    const extraImages = 1 + (n % 3);
    for (let j = 0; j < extraImages; j++) {
      images.push({
        listingId: row.id,
        url: `https://picsum.photos/seed/${row.slug}-img-${j}/800/600`,
        alt: null,
        sortOrder: j,
      });
    }

    if (tagIds.length > 0) {
      const t1 = tagIds[n % tagIds.length];
      listingTags.push({ listingId: row.id, tagId: t1 });
      if (n % 4 === 0 && tagIds.length > 1) {
        const t2 = tagIds[(n * 3 + 1) % tagIds.length];
        if (t2 !== t1) listingTags.push({ listingId: row.id, tagId: t2 });
      }
    }

    if (amenityIds.length > 0) {
      const howMany = 4 + (n % 5);
      const picked = new Set<string>();
      let a = 0;
      while (picked.size < howMany && a < amenityIds.length * 2) {
        const id = amenityIds[(n * 31 + a * 17) % amenityIds.length];
        picked.add(id);
        a++;
      }
      for (const amenityId of picked) {
        listingAmenities.push({ listingId: row.id, amenityId });
      }
    }
  }

  if (images.length) {
    for (let i = 0; i < images.length; i += 500) {
      await prisma.listingImage.createMany({ data: images.slice(i, i + 500) });
    }
  }
  if (listingTags.length) {
    await prisma.listingTag.createMany({ data: listingTags });
  }
  if (listingAmenities.length) {
    for (let i = 0; i < listingAmenities.length; i += 500) {
      await prisma.listingAmenity.createMany({ data: listingAmenities.slice(i, i + 500) });
    }
  }

  console.log(
    `Seed: create ${created.length} listări de test (${SEED_SLUG_PREFIX}0001–${SEED_SLUG_PREFIX}${String(count).padStart(4, "0")}), imagini, tag-uri, facilități.`,
  );
}

async function seedAnalytics() {
  const enabled = parseBoolEnv("SEED_ANALYTICS", true);
  if (!enabled) {
    console.log("Seed: analytics oprit (SEED_ANALYTICS=false).");
    return;
  }

  const days = parseIntEnv("SEED_ANALYTICS_DAYS", 30, 1, 90);
  const maxViewsPerListingPerDay = parseIntEnv("SEED_ANALYTICS_MAX_VIEWS_PER_LISTING_PER_DAY", 12, 0, 200);
  const clickRateWhatsapp = parseIntEnv("SEED_ANALYTICS_WA_CLICK_RATE_PCT", 6, 0, 100) / 100;
  const clickRateWebsite = parseIntEnv("SEED_ANALYTICS_WEB_CLICK_RATE_PCT", 3, 0, 100) / 100;

  const listings: Array<{ id: string; slug: string; accommodationType: string }> = await prisma.listing.findMany({
    where: { slug: { startsWith: SEED_SLUG_PREFIX } },
    select: { id: true, slug: true, accommodationType: true },
  });
  if (listings.length === 0) {
    console.log("Seed: analytics skip — nu există listări seed.");
    return;
  }

  // Clean existing analytics for seed listings (idempotent)
  const listingIds = listings.map((l) => l.id);
  await prisma.listingEvent.deleteMany({ where: { listingId: { in: listingIds } } });
  await prisma.listingPageView.deleteMany({ where: { listingId: { in: listingIds } } });

  const now = Date.now();
  const referrers = [
    { w: 45, v: "" }, // direct/empty
    { w: 28, v: "https://www.google.com/" },
    { w: 14, v: "https://www.facebook.com/" },
    { w: 8, v: "https://www.instagram.com/" },
    { w: 5, v: "https://t.co/" },
  ];

  const sessionPrefixes = ["s", "u", "m", "d"];

  const viewsBatch: Array<{
    id: string;
    listingId: string;
    userId: string | null;
    sessionId: string;
    locale: string | null;
    referrer: string | null;
    entryPath: string | null;
    entryQuery: string | null;
    startedAt: Date;
    endedAt: Date | null;
    durationMs: number | null;
  }> = [];

  const eventsBatch: Array<{
    type: "WHATSAPP_CLICK" | "WEBSITE_CLICK";
    listingId: string;
    userId: string | null;
    sessionId: string;
    locale: string | null;
    referrer: string | null;
    entryPath: string | null;
    entryQuery: string | null;
    createdAt: Date;
  }> = [];

  const chunkWrite = async () => {
    if (viewsBatch.length) {
      for (let i = 0; i < viewsBatch.length; i += 1000) {
        await prisma.listingPageView.createMany({ data: viewsBatch.slice(i, i + 1000) });
      }
      viewsBatch.length = 0;
    }
    if (eventsBatch.length) {
      for (let i = 0; i < eventsBatch.length; i += 1000) {
        await prisma.listingEvent.createMany({ data: eventsBatch.slice(i, i + 1000) });
      }
      eventsBatch.length = 0;
    }
  };

  const tipPool = ACCOMMODATION_TYPES_SEED.slice(0, Math.min(8, ACCOMMODATION_TYPES_SEED.length));
  const amenityPool = HOME_FILTER_AMENITIES.slice(0, Math.min(14, HOME_FILTER_AMENITIES.length)).map((a) => a.slug);

  for (let d = days - 1; d >= 0; d--) {
    const dayStart = new Date(now - d * 24 * 60 * 60 * 1000);
    dayStart.setHours(0, 0, 0, 0);

    for (let li = 0; li < listings.length; li++) {
      const l = listings[li]!;
      const seedBase = li * 100_000 + d * 997;

      const viewsToday = Math.floor(rand01(seedBase + 1) * (maxViewsPerListingPerDay + 1));
      for (let v = 0; v < viewsToday; v++) {
        const localSeed = seedBase + 10 + v * 31;
        const hh = Math.floor(rand01(localSeed + 1) * 24);
        const mm = Math.floor(rand01(localSeed + 2) * 60);
        const ss = Math.floor(rand01(localSeed + 3) * 60);
        const startedAt = new Date(dayStart);
        startedAt.setHours(hh, mm, ss, 0);

        // Duration: 8s .. 7m
        const durationMs = 8000 + Math.floor(rand01(localSeed + 4) * (7 * 60 * 1000 - 8000));
        const endedAt = new Date(startedAt.getTime() + durationMs);

        const sessionId = `${sessionPrefixes[(localSeed % sessionPrefixes.length)]}-${l.slug}-${d}-${v}-${Math.floor(
          rand01(localSeed + 5) * 1_000_000,
        )}`;
        const locale = rand01(localSeed + 6) < 0.15 ? "en" : "ro";
        const ref = pickWeighted(localSeed + 7, referrers);
        const referrer = ref ? ref : null;

        // Entry attribution: mimic home filters sometimes present
        const useFilters = rand01(localSeed + 8) < 0.6;
        const tip = pickWeighted(localSeed + 9, tipPool.map((t) => ({ w: 1, v: t })));
        const amenity1 = pickWeighted(localSeed + 10, amenityPool.map((a) => ({ w: 1, v: a })));
        const amenity2 = pickWeighted(localSeed + 11, amenityPool.map((a) => ({ w: 1, v: a })));
        const entryPath = useFilters ? `/${locale}` : null;
        const entryQuery = useFilters
          ? `tip=${encodeURIComponent(tip)}&amenity=${encodeURIComponent(amenity1)}&amenity=${encodeURIComponent(
              amenity2 === amenity1 ? amenityPool[(localSeed + 12) % amenityPool.length]! : amenity2,
            )}&pretMin=200&pretMax=900&src=%2F`
          : null;

        const viewId = `seed-view-${l.slug}-${d}-${v}-${Math.floor(rand01(localSeed + 13) * 1_000_000)}`;

        viewsBatch.push({
          id: viewId,
          listingId: l.id,
          userId: null,
          sessionId,
          locale,
          referrer,
          entryPath,
          entryQuery,
          startedAt,
          endedAt,
          durationMs,
        });

        // Events (clicks) – some portion of views
        if (rand01(localSeed + 14) < clickRateWhatsapp) {
          eventsBatch.push({
            type: "WHATSAPP_CLICK",
            listingId: l.id,
            userId: null,
            sessionId,
            locale,
            referrer,
            entryPath,
            entryQuery,
            createdAt: new Date(startedAt.getTime() + Math.floor(durationMs * 0.6)),
          });
        }
        if (rand01(localSeed + 15) < clickRateWebsite) {
          eventsBatch.push({
            type: "WEBSITE_CLICK",
            listingId: l.id,
            userId: null,
            sessionId,
            locale,
            referrer,
            entryPath,
            entryQuery,
            createdAt: new Date(startedAt.getTime() + Math.floor(durationMs * 0.75)),
          });
        }
      }

      if (viewsBatch.length > 2500 || eventsBatch.length > 2500) {
        await chunkWrite();
      }
    }
  }

  await chunkWrite();

  const totalViews = await prisma.listingPageView.count({ where: { listingId: { in: listingIds } } });
  const totalEvents = await prisma.listingEvent.count({ where: { listingId: { in: listingIds } } });
  console.log(`Seed: analytics generate complete — views=${totalViews}, events=${totalEvents}, days=${days}.`);
}

async function main() {
  for (let i = 0; i < HOME_FILTER_AMENITIES.length; i++) {
    const a = HOME_FILTER_AMENITIES[i];
    const nameEn = a.nameEn.trim() || null;
    await prisma.amenity.upsert({
      where: { slug: a.slug },
      create: {
        name: a.nameRo,
        nameEn,
        slug: a.slug,
        sortOrder: i,
        icon: a.iconKey,
      },
      update: { name: a.nameRo, nameEn, sortOrder: i, icon: a.iconKey },
    });
  }

  for (const c of LOCATION_SEED) {
    const county = await prisma.locationCounty.upsert({
      where: { slug: c.slug },
      create: { name: c.name, slug: c.slug },
      update: { name: c.name },
    });
    for (const city of c.cities) {
      await prisma.locationCity.upsert({
        where: {
          countyId_slug: { countyId: county.id, slug: city.slug },
        },
        create: {
          countyId: county.id,
          name: city.name,
          slug: city.slug,
        },
        update: { name: city.name },
      });
    }
  }

  for (const t of SEED_TAGS) {
    await prisma.tag.upsert({
      where: { slug: t.slug },
      create: {
        name: t.name,
        nameEn: t.nameEn,
        slug: t.slug,
        icon: t.icon,
      },
      update: { name: t.name, nameEn: t.nameEn, icon: t.icon },
    });
  }

  console.log("Seed: amenities + locații + tag-uri actualizate.");

  await seedTestListings();
  await seedAnalytics();
}

main()
  .then(() => prisma.$disconnect())
  .catch((e) => {
    console.error(e);
    prisma.$disconnect();
    process.exit(1);
  });
