import { and, desc, eq, gte, inArray, lte, asc } from "drizzle-orm"
import { db } from "@/lib/db"
import { properties, units, rent_payments, maintenance_requests, leases, expenses } from "@/lib/db/schema"
import type { DashboardStats } from "@/types"

export async function getDashboardStats(userId: string): Promise<DashboardStats> {
  // Properties + units
  const propertyRows = await db
    .select({ id: properties.id })
    .from(properties)
    .where(eq(properties.user_id, userId))
  const totalProperties = propertyRows.length

  let totalUnits = 0,
    occupiedUnits = 0,
    vacantUnits = 0

  if (totalProperties > 0) {
    const unitRows = await db
      .select({ status: units.status })
      .from(units)
      .where(eq(units.user_id, userId))
    totalUnits = unitRows.length
    occupiedUnits = unitRows.filter((u) => u.status === "occupied").length
    vacantUnits = unitRows.filter((u) => u.status === "vacant").length
  }

  // Rent this month
  const now = new Date()
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10)
  const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString().slice(0, 10)
  const lastMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString().slice(0, 10)
  const lastMonthEnd = new Date(now.getFullYear(), now.getMonth(), 0).toISOString().slice(0, 10)

  const [rentPayments, lastMonthPayments] = await Promise.all([
    db
      .select({ amount: rent_payments.amount, status: rent_payments.status })
      .from(rent_payments)
      .where(
        and(
          eq(rent_payments.user_id, userId),
          gte(rent_payments.due_date, monthStart),
          lte(rent_payments.due_date, monthEnd)
        )
      ),
    db
      .select({ amount: rent_payments.amount, status: rent_payments.status })
      .from(rent_payments)
      .where(
        and(
          eq(rent_payments.user_id, userId),
          gte(rent_payments.due_date, lastMonthStart),
          lte(rent_payments.due_date, lastMonthEnd),
          eq(rent_payments.status, "paid")
        )
      ),
  ])

  const rentCollectedThisMonth = rentPayments
    .filter((p) => p.status === "paid")
    .reduce((sum, p) => sum + Number(p.amount), 0)
  const rentCollectedLastMonth = lastMonthPayments.reduce((sum, p) => sum + Number(p.amount), 0)
  const rentPendingThisMonth = rentPayments
    .filter((p) => p.status === "pending")
    .reduce((sum, p) => sum + Number(p.amount), 0)

  // Overdue rent (all time)
  const overduePayments = await db
    .select({ amount: rent_payments.amount })
    .from(rent_payments)
    .where(and(eq(rent_payments.user_id, userId), eq(rent_payments.status, "overdue")))
  const rentOverdue = overduePayments.reduce((sum, p) => sum + Number(p.amount), 0)

  // Open maintenance
  const openMaintenance = await db
    .select({ id: maintenance_requests.id })
    .from(maintenance_requests)
    .where(
      and(
        eq(maintenance_requests.user_id, userId),
        inArray(maintenance_requests.status, ["open", "in_progress"])
      )
    )

  // Expiring leases (within 60 days)
  const in60Days = new Date()
  in60Days.setDate(in60Days.getDate() + 60)
  const expiring = await db
    .select({ id: leases.id })
    .from(leases)
    .where(
      and(
        eq(leases.user_id, userId),
        eq(leases.status, "active"),
        lte(leases.lease_end, in60Days.toISOString().slice(0, 10))
      )
    )

  const occupancyRate = totalUnits > 0 ? Math.round((occupiedUnits / totalUnits) * 100) : 0

  return {
    totalProperties,
    totalUnits,
    occupiedUnits,
    vacantUnits,
    occupancyRate,
    rentCollectedThisMonth,
    rentCollectedLastMonth,
    rentPendingThisMonth,
    rentOverdue,
    openMaintenanceRequests: openMaintenance.length,
    expiringLeases: expiring.length,
  }
}

export async function getRecentRentPayments(userId: string, limit = 5) {
  return db.query.rent_payments.findMany({
    where: eq(rent_payments.user_id, userId),
    with: {
      tenant: { columns: { first_name: true, last_name: true } },
      property: { columns: { name: true } },
    },
    orderBy: desc(rent_payments.created_at),
    limit,
  })
}

export async function getOpenMaintenanceRequests(userId: string, limit = 5) {
  return db.query.maintenance_requests.findMany({
    where: and(
      eq(maintenance_requests.user_id, userId),
      inArray(maintenance_requests.status, ["open", "in_progress"])
    ),
    with: {
      property: { columns: { name: true } },
      tenant: { columns: { first_name: true, last_name: true } },
    },
    orderBy: desc(maintenance_requests.created_at),
    limit,
  })
}

export async function getMonthlyRevenue(userId: string) {
  const sixMonthsAgo = new Date()
  sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 5)
  sixMonthsAgo.setDate(1)

  const data = await db
    .select({ amount: rent_payments.amount, due_date: rent_payments.due_date })
    .from(rent_payments)
    .where(
      and(
        eq(rent_payments.user_id, userId),
        eq(rent_payments.status, "paid"),
        gte(rent_payments.due_date, sixMonthsAgo.toISOString().slice(0, 10))
      )
    )

  const months: Record<string, number> = {}
  for (let i = 5; i >= 0; i--) {
    const d = new Date()
    d.setMonth(d.getMonth() - i)
    const key = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
    months[key] = 0
  }
  data.forEach((p) => {
    const key = p.due_date.slice(0, 7)
    if (key in months) months[key] += Number(p.amount)
  })

  return Object.entries(months).map(([month, amount]) => ({
    month,
    label: new Date(month + "-01").toLocaleDateString("en-US", { month: "short" }),
    amount,
  }))
}

export async function getExpenseBreakdown(userId: string) {
  const sixMonthsAgo = new Date()
  sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 5)
  sixMonthsAgo.setDate(1)

  const data = await db
    .select({ category: expenses.category, amount: expenses.amount })
    .from(expenses)
    .where(
      and(
        eq(expenses.user_id, userId),
        gte(expenses.expense_date, sixMonthsAgo.toISOString().slice(0, 10))
      )
    )

  const totals: Record<string, number> = {}
  data.forEach((e) => {
    totals[e.category] = (totals[e.category] ?? 0) + Number(e.amount)
  })

  return Object.entries(totals)
    .map(([category, amount]) => ({ category, amount }))
    .sort((a, b) => b.amount - a.amount)
}

export async function getExpiringLeases(userId: string, limit = 5) {
  const in60Days = new Date()
  in60Days.setDate(in60Days.getDate() + 60)

  return db.query.leases.findMany({
    where: and(
      eq(leases.user_id, userId),
      eq(leases.status, "active"),
      lte(leases.lease_end, in60Days.toISOString().slice(0, 10))
    ),
    with: {
      tenant: { columns: { first_name: true, last_name: true } },
      property: { columns: { name: true } },
    },
    orderBy: asc(leases.lease_end),
    limit,
  })
}
