/**
 * Seed 10 real, login-capable users — each with a full graph of activity.
 *
 * Passwords are hashed with Better Auth's own `hashPassword` (node scrypt),
 * and credential accounts are written in the exact shape Better Auth expects
 * (`providerId: "credential"`, `accountId: <userId>`), so every seeded user can
 * actually log in. NO plaintext passwords are ever stored.
 *
 * Run:  npx tsx scripts/seed-users.ts
 *
 * Re-runnable: existing users with the seeded emails are deleted first (FK
 * cascades wipe their data), then recreated.
 */
import { config } from "dotenv"
config({ path: ".env.local" })

// The hardened db layer now defaults to verified TLS. The dev DATABASE_URL is a
// plaintext Postgres, so opt back into the original plaintext behaviour for the
// seed unless the operator has set DATABASE_SSL explicitly.
process.env.DATABASE_SSL = process.env.DATABASE_SSL ?? "disable"

import { randomUUID } from "node:crypto"

// ── deterministic-ish helpers ────────────────────────────────────────────────
const ymd = (d: Date) => d.toISOString().slice(0, 10)
const iso = (d: Date) => d.toISOString()
const daysAgo = (n: number) => {
  const d = new Date()
  d.setDate(d.getDate() - n)
  return d
}
const monthsFromNow = (n: number, day = 1) => {
  const now = new Date()
  return new Date(now.getFullYear(), now.getMonth() + n, day)
}
const pick = <T>(arr: readonly T[], i: number) => arr[i % arr.length]
const randInt = (min: number, max: number) => min + Math.floor(Math.random() * (max - min + 1))

// ── data pools ───────────────────────────────────────────────────────────────
const LANDLORDS = [
  { name: "Alice Thompson",  company: "Thompson Property Group" },
  { name: "Brian Okafor",    company: "Okafor Rentals" },
  { name: "Carla Mendes",    company: "Mendes Holdings" },
  { name: "Daniel Schwartz",  company: "Schwartz & Co Estates" },
  { name: "Elena Petrova",   company: "Petrova Living" },
  { name: "Frank Nguyen",    company: "Nguyen Family Homes" },
  { name: "Grace Adeyemi",   company: "Adeyemi Lettings" },
  { name: "Hassan Ali",      company: "Ali Property Partners" },
  { name: "Isabel Romero",   company: "Romero Residential" },
  { name: "Jack Sullivan",   company: "Sullivan Asset Mgmt" },
] as const

const PLANS = ["starter", "pro", "landlord", "lifetime"] as const

const CITIES = [
  { city: "Austin",      state: "TX", zip: "78701" },
  { city: "Denver",      state: "CO", zip: "80202" },
  { city: "Portland",    state: "OR", zip: "97205" },
  { city: "Nashville",   state: "TN", zip: "37203" },
  { city: "Raleigh",     state: "NC", zip: "27601" },
  { city: "Phoenix",     state: "AZ", zip: "85004" },
  { city: "Columbus",    state: "OH", zip: "43215" },
  { city: "Sacramento",  state: "CA", zip: "95814" },
] as const

const STREETS = ["Maple St", "Oak Ave", "Riverside Dr", "Crestwood Ln", "Sunset Blvd", "Birch Rd", "Elm Ct", "Hillcrest Way"]
const PROP_LABELS = ["Court Apartments", "Flats", "Villa", "Residences", "Lofts", "Terrace", "House", "Commons"]

const TENANT_FIRST = ["Sarah", "Marcus", "Priya", "David", "Emily", "James", "Nina", "Omar", "Lucia", "Tom", "Aisha", "Ben", "Mia", "Carlos", "Zoe"]
const TENANT_LAST  = ["Johnson", "Lee", "Patel", "Kim", "Carter", "Williams", "Novak", "Hassan", "Garcia", "Brooks", "Khan", "Reed", "Chen", "Lopez", "Park"]

const MAINT = [
  { title: "Leaking kitchen faucet",   description: "Faucet drips constantly; water pooling under the sink.", category: "plumbing",   priority: "medium" },
  { title: "Heating unit not working", description: "Bedroom wall heater stopped working; cold at night.",    category: "hvac",       priority: "high" },
  { title: "Broken window latch",      description: "Living room window latch broken; won't close fully.",     category: "general",    priority: "medium" },
  { title: "Garage door motor failure", description: "Opener clicks but the door won't lift.",                 category: "electrical", priority: "high" },
  { title: "Paint peeling in bathroom", description: "Ceiling paint bubbling near the shower; moisture issue.", category: "general",    priority: "low" },
  { title: "Dishwasher won't drain",   description: "Standing water left after every cycle.",                  category: "appliance",  priority: "medium" },
] as const

const EXPENSES = [
  { category: "repairs",    description: "HVAC inspection and repair",        amount: 320 },
  { category: "management", description: "Common area deep clean",            amount: 250 },
  { category: "insurance",  description: "Building insurance premium",        amount: 1200 },
  { category: "utilities",  description: "Common area electricity",           amount: 145 },
  { category: "taxes",      description: "Quarterly property tax payment",    amount: 2100 },
  { category: "supplies",   description: "Smoke detectors + batteries",       amount: 90 },
] as const

const PAY_METHODS = ["bank_transfer", "card", "stripe", "cash"]

// ── main ─────────────────────────────────────────────────────────────────────
async function main() {
  const { db, pool } = await import("../lib/db")
  const s = await import("../lib/db/schema")
  const { inArray } = await import("drizzle-orm")
  const { hashPassword } = await import("better-auth/crypto")

  const PASSWORD = "Password123!"
  const emails = LANDLORDS.map((_, i) => `landlord${i + 1}@demo.test`)

  console.log("Cleaning any previous seed users (cascades to their data)…")
  await db.delete(s.user).where(inArray(s.user.email, emails))

  const summary: { email: string; plan: string; properties: number; tenants: number; payments: number }[] = []

  for (let i = 0; i < LANDLORDS.length; i++) {
    const userId = randomUUID()
    const email = emails[i]
    const { name, company } = LANDLORDS[i]
    const plan = PLANS[i % PLANS.length]
    const createdAt = daysAgo(randInt(60, 240))

    // ── Better Auth: user + hashed-password credential account + app profile ──
    const passwordHash = await hashPassword(PASSWORD) // node scrypt, salt embedded
    await db.insert(s.user).values({
      id: userId, name, email, emailVerified: true, createdAt, updatedAt: createdAt,
    })
    await db.insert(s.account).values({
      id: randomUUID(),
      accountId: userId,
      providerId: "credential",
      userId,
      password: passwordHash,
      createdAt, updatedAt: createdAt,
    })
    await db.insert(s.profiles).values({
      id: userId, email, full_name: name, company_name: company,
      plan, onboarding_completed: true,
    })

    const activity: (typeof s.activity_log.$inferInsert)[] = []
    let tenantCount = 0
    let paymentCount = 0
    const city = pick(CITIES, i)

    const numProps = 1 + (i % 3) // 1..3 properties
    for (let p = 0; p < numProps; p++) {
      const propId = randomUUID()
      const propName = `${pick(STREETS, i + p).split(" ")[0]} ${pick(PROP_LABELS, i + p)}`
      const numUnits = randInt(1, 3)

      await db.insert(s.properties).values({
        id: propId, user_id: userId, name: propName,
        address_line1: `${randInt(10, 990)} ${pick(STREETS, i + p)}`,
        city: city.city, state: city.state, postal_code: city.zip,
        property_type: "residential", total_units: numUnits,
        created_at: iso(createdAt),
      })
      activity.push({
        user_id: userId, type: "property_added", title: `Added property: ${propName}`,
        entity_type: "property", entity_id: propId, created_at: iso(daysAgo(randInt(50, 200))),
      })

      for (let u = 0; u < numUnits; u++) {
        const unitId = randomUUID()
        const rent = randInt(11, 28) * 100 // 1100..2800
        const occupied = Math.random() < 0.8
        const tenantId = occupied ? randomUUID() : null

        await db.insert(s.units).values({
          id: unitId, property_id: propId, user_id: userId,
          unit_number: `${u + 1}${String.fromCharCode(65 + (i % 3))}`,
          bedrooms: randInt(1, 3), bathrooms: randInt(1, 2), sq_ft: randInt(550, 1300),
          rent_amount: rent, status: occupied ? "occupied" : "vacant",
          current_tenant_id: tenantId,
        })
        if (!occupied || !tenantId) continue

        // Tenant
        const first = pick(TENANT_FIRST, i * 3 + u + p)
        const last = pick(TENANT_LAST, i * 2 + u + p)
        const moveIn = monthsFromNow(-randInt(6, 22), 1)
        await db.insert(s.tenants).values({
          id: tenantId, user_id: userId, property_id: propId, unit_id: unitId,
          first_name: first, last_name: last,
          email: `${first.toLowerCase()}.${last.toLowerCase()}${i}${u}@example.com`,
          phone: `+1 (512) 555-0${randInt(100, 999)}`,
          move_in_date: ymd(moveIn), status: "active",
          emergency_contact_name: `${pick(TENANT_FIRST, i + u + 5)} ${last}`,
          emergency_contact_phone: `+1 (512) 555-0${randInt(100, 999)}`,
        })
        tenantCount++
        activity.push({
          user_id: userId, type: "tenant_added", title: `New tenant: ${first} ${last}`,
          entity_type: "tenant", entity_id: tenantId, created_at: iso(daysAgo(randInt(20, 180))),
        })

        // Lease (some expiring within 60 days to trigger alerts)
        const leaseId = randomUUID()
        const leaseEnd = monthsFromNow(i % 4 === 0 ? randInt(1, 2) : randInt(8, 16), randInt(1, 28))
        await db.insert(s.leases).values({
          id: leaseId, user_id: userId, tenant_id: tenantId, property_id: propId, unit_id: unitId,
          lease_start: ymd(moveIn), lease_end: ymd(leaseEnd),
          rent_amount: rent, security_deposit: rent * 2, lease_type: "fixed", status: "active",
        })
        activity.push({
          user_id: userId, type: "lease_created", title: `Lease signed — Unit ${u + 1}`,
          entity_type: "lease", entity_id: leaseId, created_at: iso(daysAgo(randInt(20, 180))),
        })

        // 6 months of rent payments
        for (let m = 5; m >= 0; m--) {
          const due = monthsFromNow(-m, 1)
          let status: "paid" | "pending" | "overdue" = "paid"
          if (m === 0) status = "pending"
          else if (m === 1 && Math.random() < 0.25) status = "overdue"
          await db.insert(s.rent_payments).values({
            id: randomUUID(), user_id: userId, tenant_id: tenantId, property_id: propId, unit_id: unitId,
            amount: rent, due_date: ymd(due),
            paid_date: status === "paid" ? ymd(new Date(due.getFullYear(), due.getMonth(), randInt(1, 4))) : null,
            status, payment_method: status === "paid" ? pick(PAY_METHODS, m) : null,
          })
          paymentCount++
          if (status === "paid") {
            activity.push({
              user_id: userId, type: "rent_paid", title: `Rent paid — ${first} ${last}`,
              description: `$${rent.toLocaleString()} · ${pick(PAY_METHODS, m)}`,
              entity_type: "rent", created_at: iso(new Date(due.getFullYear(), due.getMonth(), randInt(1, 4))),
            })
          }
        }

        // ~40% of units get a maintenance request
        if (Math.random() < 0.4) {
          const mr = pick(MAINT, i + u + p)
          const mid = randomUUID()
          const opened = daysAgo(randInt(2, 40))
          const resolved = Math.random() < 0.5
          await db.insert(s.maintenance_requests).values({
            id: mid, user_id: userId, tenant_id: tenantId, property_id: propId, unit_id: unitId,
            title: mr.title, description: mr.description,
            category: mr.category as typeof s.maintenance_requests.$inferInsert.category,
            priority: mr.priority as typeof s.maintenance_requests.$inferInsert.priority,
            status: resolved ? "resolved" : "open",
            resolved_at: resolved ? iso(daysAgo(randInt(0, 1))) : null,
            resolution_notes: resolved ? "Completed by contractor." : null,
            actual_cost: resolved ? randInt(80, 500) : null,
            created_at: iso(opened),
          })
          activity.push({
            user_id: userId,
            type: resolved ? "maintenance_resolved" : "maintenance_opened",
            title: `${resolved ? "Resolved" : "Opened"}: ${mr.title}`,
            entity_type: "maintenance", entity_id: mid, created_at: iso(opened),
          })
        }
      }

      // 2-3 expenses per property
      const numExp = randInt(2, 3)
      for (let e = 0; e < numExp; e++) {
        const ex = pick(EXPENSES, i + p + e)
        const exDate = daysAgo(randInt(5, 120))
        await db.insert(s.expenses).values({
          id: randomUUID(), user_id: userId, property_id: propId,
          category: ex.category as typeof s.expenses.$inferInsert.category,
          description: `${ex.description} — ${propName}`, amount: ex.amount,
          expense_date: ymd(exDate), vendor: pick(["HVAC Pro", "CleanCo", "State Farm", "City Energy", "County Tax"], e),
          is_recurring: ex.category === "insurance" || ex.category === "utilities",
        })
        activity.push({
          user_id: userId, type: "expense_added", title: `Expense: ${ex.description}`,
          description: `$${ex.amount.toLocaleString()} · ${ex.category}`,
          entity_type: "expense", created_at: iso(exDate),
        })
      }
    }

    if (activity.length) await db.insert(s.activity_log).values(activity)

    summary.push({ email, plan, properties: numProps, tenants: tenantCount, payments: paymentCount })
    console.log(`  ✓ ${email}  [${plan}]  ${numProps} properties · ${tenantCount} tenants · ${paymentCount} payments · ${activity.length} activity events`)
  }

  console.log("\n────────────────────────────────────────────")
  console.log("Seed complete. All 10 users can log in with:")
  console.log(`  Password (all accounts): ${PASSWORD}`)
  console.table(summary)
  console.log("Passwords are stored hashed (Better Auth node scrypt). No plaintext in the DB.")

  await pool.end()
}

main().catch((err) => {
  console.error("\nSeed failed:", err)
  process.exit(1)
})
