// prisma/seed.js
const { PrismaClient, DealStatus, SaleType, AffiliateType } = require("@prisma/client")
const fs = require("fs")
const path = require("path")

const prisma = new PrismaClient()

function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min
}

// Stabil gerçek foto linkleri (redirect yok, hotlink derdi az)
function realImage(seed, w = 1200, h = 900) {
  return `https://picsum.photos/seed/${encodeURIComponent(seed)}/${w}/${h}`
}

// Son N gün içinde random tarih
function randomDateWithinLastDays(days = 5) {
  const now = Date.now()
  const maxBack = days * 24 * 60 * 60 * 1000
  const offset = randInt(0, maxBack)
  return new Date(now - offset)
}

function normalizeSlug(s) {
  return String(s ?? "").trim().toLowerCase()
}

function toNumberOrNull(v) {
  if (v === null || v === undefined || v === "") return null
  const n = Number(v)
  return Number.isFinite(n) ? n : null
}

async function upsertTagBySlug(slug, name) {
  const s = normalizeSlug(slug)
  return prisma.tag.upsert({
    where: { slug: s },
    update: { name },
    create: { slug: s, name },
  })
}

async function attachTagsToDeal(dealId, tagSlugs) {
  const unique = [...new Set((tagSlugs ?? []).map(normalizeSlug).filter(Boolean))]
  if (!unique.length) return

  const tags = await prisma.$transaction(
    unique.map((slug) =>
      prisma.tag.upsert({
        where: { slug },
        update: {},
        create: { slug, name: slug },
      })
    )
  )

  await prisma.dealTag.createMany({
    data: tags.map((t) => ({ dealId, tagId: t.id })),
    skipDuplicates: true,
  })
}

function loadCategoriesJson(filePath) {
  const raw = fs.readFileSync(filePath, "utf-8")
  const arr = JSON.parse(raw)

  if (!Array.isArray(arr)) throw new Error("categories.json array olmalı")

  const cats = arr.map((c) => ({
    id: Number(c.id),
    name: String(c.name ?? "").trim(),
    slug: normalizeSlug(c.slug),
    description: c.description,
    parentId: c.parentId === null || c.parentId === undefined ? null : Number(c.parentId),
  }))

  for (const c of cats) {
    if (!Number.isInteger(c.id)) throw new Error(`Category id invalid: ${c.id}`)
    if (!c.name) throw new Error(`Category name boş olamaz (id=${c.id})`)
    if (!c.slug) throw new Error(`Category slug boş olamaz (id=${c.id})`)
  }

  const has0 = cats.some((c) => c.id === 0)
  if (!has0) {
    cats.unshift({ id: 0, name: "Undefined", slug: "undefined", parentId: null })
  }

  const idSet = new Set()
  const slugSet = new Set()
  for (const c of cats) {
    if (idSet.has(c.id)) throw new Error(`categories.json duplicate id: ${c.id}`)
    idSet.add(c.id)
    if (slugSet.has(c.slug)) throw new Error(`categories.json duplicate slug: ${c.slug}`)
    slugSet.add(c.slug)
  }

  return cats
}

async function seedCategoriesFromJson(categoriesFilePath) {
  const categories = loadCategoriesJson(categoriesFilePath)

  await prisma.$transaction(
    categories.map((c) =>
      prisma.category.upsert({
        where: { id: c.id },
        update: {
          name: c.name,
          slug: c.slug,
          description: c.description,
        },
        create: {
          id: c.id,
          name: c.name,
          slug: c.slug,
          description: c.description,
          parentId: null,
        },
      })
    ),
    { timeout: 60_000 }
  )

  await prisma.$transaction(
    categories.map((c) =>
      prisma.category.update({
        where: { id: c.id },
        data: { parentId: c.parentId },
      })
    ),
    { timeout: 60_000 }
  )

  await prisma.$executeRawUnsafe(`
    SELECT setval(
      pg_get_serial_sequence('"Category"', 'id'),
      COALESCE((SELECT MAX(id) FROM "Category"), 0) + 1,
      false
    );
  `)

  return { count: categories.length }
}

function loadDealsJson(filePath) {
  const raw = fs.readFileSync(filePath, "utf-8")
  const arr = JSON.parse(raw)

  if (!Array.isArray(arr)) throw new Error("deals.json array olmalı")

  const items = arr.map((d, idx) => {
    const title = String(d.title ?? "").trim()
    const url = String(d.url ?? "").trim()
    const q = String(d.q ?? "").trim()

    const price = toNumberOrNull(d.price)
    const originalPrice = toNumberOrNull(d.originalPrice)
    const shippingPrice = toNumberOrNull(d.shippingPrice)

    if (!title) throw new Error(`deals.json: title boş (index=${idx})`)
    if (!url) throw new Error(`deals.json: url boş (index=${idx})`)
    if (price === null) throw new Error(`deals.json: price invalid (index=${idx})`)

    // Mantık: originalPrice varsa price'dan küçük olamaz
    if (originalPrice !== null && originalPrice < price) {
      throw new Error(`deals.json: originalPrice < price (index=${idx})`)
    }

    return {
      title,
      url,
      q,
      price,
      originalPrice,
      shippingPrice,
    }
  })

  // url unique olsun (seed idempotent)
  const urlSet = new Set()
  for (const it of items) {
    if (urlSet.has(it.url)) throw new Error(`deals.json duplicate url: ${it.url}`)
    urlSet.add(it.url)
  }

  return items
}

// deals.json’dan seed + her deal’a 3 foto + score 0-200 + tarih dağılımı:
// - %70: son 5 gün
// - %30: 9-11 gün önce
async function seedDealsFromJson({ userId, sellerId, categoryId, dealsFilePath }) {
  const baseItems = loadDealsJson(dealsFilePath)

  // 30 adet olacak şekilde çoğalt (title/url benzersizleşsin)
  const items = []
  for (let i = 0; i < 30; i++) {
    const base = baseItems[i % baseItems.length]
    const n = i + 1

    // price'ı hafif oynat (base price üzerinden)
    const price = Number((base.price * (0.9 + randInt(0, 30) / 100)).toFixed(2))

    // originalPrice varsa, yeni price'a göre ölçekle (mantık korunur)
    let originalPrice = null
    if (base.originalPrice !== null && base.originalPrice !== undefined) {
      const ratio = base.originalPrice / base.price // >= 1 olmalı
      originalPrice = Number((price * ratio).toFixed(2))
      if (originalPrice < price) originalPrice = Number((price * 1.05).toFixed(2))
    }

    // shippingPrice varsa bazen aynen, bazen 0/ufak varyasyon (ama null değilse)
    let shippingPrice = null
    if (base.shippingPrice !== null && base.shippingPrice !== undefined) {
      // 70% aynı, 30% küçük oynat
      if (Math.random() < 0.7) {
        shippingPrice = Number(base.shippingPrice)
      } else {
        const candidates = [0, 19.9, 29.9, 39.9, 49.9, 59.9]
        shippingPrice = candidates[randInt(0, candidates.length - 1)]
      }
    }

    items.push({
      title: `${base.title} #${n}`,
      price,
      originalPrice,
      shippingPrice,
      url: `${base.url}${base.url.includes("?") ? "&" : "?"}seed=${n}`,
      q: base.q || "product",
    })
  }

  for (let i = 0; i < items.length; i++) {
    const it = items[i]

    const older = Math.random() < 0.3
    const createdAt = older
      ? new Date(Date.now() - randInt(9, 11) * 24 * 60 * 60 * 1000 - randInt(0, 12) * 60 * 60 * 1000)
      : randomDateWithinLastDays(5)

    const dealData = {
      title: it.title,
      description: "Seed test deal açıklaması (otomatik üretim).",
      url: it.url,
      price: it.price,
      originalPrice: it.originalPrice ?? null,
      shippingPrice: it.shippingPrice ?? null,
      status: DealStatus.ACTIVE,
      saletype: SaleType.ONLINE,
      affiliateType: AffiliateType.NON_AFFILIATE,
      commentCount: randInt(0, 25),
      userId,
      sellerId,
      categoryId,
      score: randInt(0, 200),
      createdAt,
    }

    const existing = await prisma.deal.findFirst({
      where: { url: it.url },
      select: { id: true },
    })

    const deal = existing
      ? await prisma.deal.update({ where: { id: existing.id }, data: dealData })
      : await prisma.deal.create({ data: dealData })

    await prisma.dealImage.deleteMany({ where: { dealId: deal.id } })
    await prisma.dealImage.createMany({
      data: [
        { dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-1`), order: 0 },
        { dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-2`), order: 1 },
        { dealId: deal.id, imageUrl: realImage(`${it.q}-${i}-3`), order: 2 },
      ],
    })
  }
}

async function main() {
  const hashedPassword = "$2b$10$PVfLq2NmcGmKbhE5VK3yNeVj46O/1w2p/2BNu4h1CYacqSgkCcoCW"

  // ---------- USERS ----------
  const admin = await prisma.user.upsert({
    where: { email: "test" },
    update: {},
    create: {
      username: "test",
      email: "test",
      passwordHash: hashedPassword,
      role: "ADMIN",
    },
  })

  const user = await prisma.user.upsert({
    where: { email: "test2" },
    update: {},
    create: {
      username: "test2",
      email: "test2",
      passwordHash: hashedPassword,
      role: "USER",
    },
  })

  // ---------- SELLER ----------
  const amazon = await prisma.seller.upsert({
    where: { name: "Amazon" },
    update: { isActive: true },
    create: {
      name: "Amazon",
      url: "https://www.amazon.com.tr",
      sellerLogo:"https://1000logos.net/wp-content/uploads/2016/10/Amazon-logo-meaning.jpg",
      isActive: true,
      createdById: admin.id,
    },
  })

  // ---------- SELLER DOMAINS ----------
  const domains = ["amazon.com", "amazon.com.tr"]
  for (const domain of domains) {
    await prisma.sellerDomain.upsert({
      where: { domain },
      update: { sellerId: amazon.id },
      create: {
        domain,
        sellerId: amazon.id,
        createdById: admin.id,
      },
    })
  }

  // ---------- CATEGORIES (FROM JSON) ----------
  const categoriesFilePath = path.join(__dirname, "categories.json")
  const { count } = await seedCategoriesFromJson(categoriesFilePath)

  const catSSD = await prisma.category.findUnique({
    where: { slug: "pc-ssd" },
    select: { id: true },
  })

  // ---------- TAGS ----------
  await upsertTagBySlug("ssd", "SSD")
  await upsertTagBySlug("nvme", "NVMe")
  await upsertTagBySlug("1tb", "1TB")

  // ---------- DEAL (tek örnek) ----------
  const dealUrl = "https://www.amazon.com.tr/dp/test"
  const existing = await prisma.deal.findFirst({
    where: { url: dealUrl },
    select: { id: true },
  })

  const dealData = {
    title: "Samsung SSD 1TB",
    description: "Test deal açıklaması",
    url: dealUrl,
    price: 1299.99,
    originalPrice: 1499.99, // örnek
    shippingPrice: 0, // örnek
    status: DealStatus.ACTIVE,
    saletype: SaleType.ONLINE,
    affiliateType: AffiliateType.NON_AFFILIATE,
    commentCount: 1,
    userId: user.id,
    sellerId: amazon.id,
    categoryId: catSSD?.id ?? 0,
    // score: randInt(0, 200), // modelinde varsa aç
  }

  const deal = existing
    ? await prisma.deal.update({ where: { id: existing.id }, data: dealData })
    : await prisma.deal.create({ data: dealData })

  // ---------- DEAL TAGS ----------
  await attachTagsToDeal(deal.id, ["ssd", "nvme", "1tb"])

  // ---------- DEAL IMAGES (tek örnek) ----------
  await prisma.dealImage.deleteMany({ where: { dealId: deal.id } })
  await prisma.dealImage.createMany({
    data: [
      { dealId: deal.id, imageUrl: realImage("nvme-ssd-single-1"), order: 0 },
      { dealId: deal.id, imageUrl: realImage("nvme-ssd-single-2"), order: 1 },
      { dealId: deal.id, imageUrl: realImage("nvme-ssd-single-3"), order: 2 },
    ],
  })

  // ✅ ---------- deals.json’dan 30 DEAL ÜRET ----------
  const dealsFilePath = path.join(__dirname, "deals.json")
  await seedDealsFromJson({
    userId: user.id,
    sellerId: amazon.id,
    categoryId: catSSD?.id ?? 0,
    dealsFilePath,
  })

  // ---------- VOTE ----------
  await prisma.dealVote.upsert({
    where: { dealId_userId: { dealId: deal.id, userId: admin.id } },
    update: { voteType: 1, lastVotedAt: new Date() },
    create: { dealId: deal.id, userId: admin.id, voteType: 1 },
  })

  // ---------- COMMENT ----------
  const hasComment = await prisma.comment.findFirst({
    where: { dealId: deal.id, userId: admin.id, text: "Gerçekten iyi fırsat" },
    select: { id: true },
  })
  if (!hasComment) {
    await prisma.comment.create({
      data: { text: "Gerçekten iyi fırsat", userId: admin.id, dealId: deal.id },
    })
  }

  console.log(`✅ Seed tamamlandı (categories.json yüklendi: ${count} kategori)`)
  console.log("✅ deals.json baz alınarak 30 adet test deal + 3'er görsel + score(0-200) + tarih dağılımı eklendi/güncellendi")
}

main()
  .catch((err) => {
    console.error(err)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
