import { jsPDF } from 'jspdf'
import { formatCurrency, formatNumber } from './locale'

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export interface ReportProjectRow {
  name: string
  color: string
  hours: number
  rate: number
  earnings: number
  percentage: number
}

export interface HoursReportData {
  dateRange: { start: string; end: string }
  totalHours: number
  totalEarnings: number
  billableHours: number
  nonBillableHours: number
  projects: ReportProjectRow[]
}

export interface ProfitabilityReportRow {
  project_name: string
  client_name: string | null
  total_hours: number
  hourly_rate: number
  revenue: number
  expenses: number
  net_profit: number
  budget_hours: number | null
  budget_used_pct: number | null
}

export interface ProfitabilityReportData {
  dateRange: { start: string; end: string }
  totalRevenue: number
  totalExpenses: number
  totalNet: number
  totalHours: number
  avgRate: number
  rows: ProfitabilityReportRow[]
}

export interface ExpenseReportData {
  dateRange: { start: string; end: string }
  totalAmount: number
  invoicedAmount: number
  uninvoicedAmount: number
  byCategory: { category: string; amount: number; percentage: number }[]
  byProject: { name: string; color: string; amount: number; percentage: number }[]
}

export interface PatternsReportData {
  dateRange: { start: string; end: string }
  heatmap: number[][]
  peakDay: string
  peakHour: string
}

// ---------------------------------------------------------------------------
// Shared PDF helpers
// ---------------------------------------------------------------------------

function hexToRgb(hex: string): [number, number, number] {
  const h = hex.replace('#', '')
  return [
    parseInt(h.substring(0, 2), 16),
    parseInt(h.substring(2, 4), 16),
    parseInt(h.substring(4, 6), 16),
  ]
}

function setText(doc: jsPDF, hex: string) {
  const [r, g, b] = hexToRgb(hex)
  doc.setTextColor(r, g, b)
}

function setFill(doc: jsPDF, hex: string) {
  const [r, g, b] = hexToRgb(hex)
  doc.setFillColor(r, g, b)
}

const PAGE_W = 210
const PAGE_H = 297
const MARGIN = 15
const CONTENT_W = PAGE_W - MARGIN * 2

function drawHeader(doc: jsPDF, title: string, dateRange: { start: string; end: string }): number {
  let y = MARGIN

  doc.setFontSize(18)
  setText(doc, '#E5E7EB')
  doc.text(title, MARGIN, y + 6)
  y += 10

  doc.setFontSize(9)
  setText(doc, '#9CA3AF')
  doc.text(`${dateRange.start} to ${dateRange.end}`, MARGIN, y + 4)
  y += 10

  setFill(doc, '#374151')
  doc.rect(MARGIN, y, CONTENT_W, 0.3, 'F')
  y += 6

  return y
}

function drawStatBox(doc: jsPDF, x: number, y: number, w: number, label: string, value: string) {
  setFill(doc, '#1F2937')
  doc.roundedRect(x, y, w, 18, 2, 2, 'F')

  doc.setFontSize(7)
  setText(doc, '#9CA3AF')
  doc.text(label.toUpperCase(), x + 4, y + 6)

  doc.setFontSize(11)
  setText(doc, '#F9FAFB')
  doc.text(value, x + 4, y + 14)
}

function drawTableHeader(doc: jsPDF, y: number, cols: { label: string; x: number; w: number; align?: string }[]): number {
  setFill(doc, '#1F2937')
  doc.rect(MARGIN, y, CONTENT_W, 7, 'F')

  doc.setFontSize(6.5)
  setText(doc, '#9CA3AF')
  for (const col of cols) {
    if (col.align === 'right') {
      doc.text(col.label.toUpperCase(), col.x + col.w - 2, y + 5, { align: 'right' })
    } else {
      doc.text(col.label.toUpperCase(), col.x + 2, y + 5)
    }
  }
  return y + 7
}

function checkPageBreak(doc: jsPDF, y: number, needed: number): number {
  if (y + needed > PAGE_H - MARGIN) {
    doc.addPage()
    setFill(doc, '#0D1117')
    doc.rect(0, 0, PAGE_W, PAGE_H, 'F')
    return MARGIN
  }
  return y
}

// ---------------------------------------------------------------------------
// Hours Report
// ---------------------------------------------------------------------------

function renderHoursReport(doc: jsPDF, data: HoursReportData) {
  let y = drawHeader(doc, 'Hours Report', data.dateRange)

  const boxW = (CONTENT_W - 6) / 4
  drawStatBox(doc, MARGIN, y, boxW, 'Total Hours', formatNumber(data.totalHours, 1) + 'h')
  drawStatBox(doc, MARGIN + boxW + 2, y, boxW, 'Earnings', formatCurrency(data.totalEarnings))
  drawStatBox(doc, MARGIN + (boxW + 2) * 2, y, boxW, 'Billable', formatNumber(data.billableHours, 1) + 'h')
  drawStatBox(doc, MARGIN + (boxW + 2) * 3, y, boxW, 'Non-Billable', formatNumber(data.nonBillableHours, 1) + 'h')
  y += 24

  // Bar chart
  if (data.projects.length > 0) {
    const barAreaH = Math.min(data.projects.length * 10, 80)
    y = checkPageBreak(doc, y, barAreaH + 10)

    doc.setFontSize(9)
    setText(doc, '#E5E7EB')
    doc.text('Hours by Project', MARGIN, y + 4)
    y += 8

    const maxHours = Math.max(...data.projects.map(p => p.hours))
    const barMaxW = CONTENT_W - 50
    for (const proj of data.projects) {
      y = checkPageBreak(doc, y, 10)
      const barW = maxHours > 0 ? (proj.hours / maxHours) * barMaxW : 0

      doc.setFontSize(7)
      setText(doc, '#D1D5DB')
      doc.text(proj.name.substring(0, 25), MARGIN, y + 4)

      setFill(doc, proj.color || '#F59E0B')
      doc.roundedRect(MARGIN + 48, y, Math.max(barW, 1), 5, 1, 1, 'F')

      setText(doc, '#9CA3AF')
      doc.text(formatNumber(proj.hours, 1) + 'h', MARGIN + 50 + barW, y + 4)
      y += 8
    }
    y += 4
  }

  // Project table
  y = checkPageBreak(doc, y, 20)
  doc.setFontSize(9)
  setText(doc, '#E5E7EB')
  doc.text('Project Breakdown', MARGIN, y + 4)
  y += 8

  const cols = [
    { label: 'Project', x: MARGIN, w: 60 },
    { label: 'Hours', x: MARGIN + 60, w: 30, align: 'right' },
    { label: 'Rate', x: MARGIN + 90, w: 35, align: 'right' },
    { label: 'Earnings', x: MARGIN + 125, w: 35, align: 'right' },
    { label: '%', x: MARGIN + 160, w: 20, align: 'right' },
  ]
  y = drawTableHeader(doc, y, cols)

  doc.setFontSize(7)
  for (let i = 0; i < data.projects.length; i++) {
    y = checkPageBreak(doc, y, 7)
    const p = data.projects[i]

    if (i % 2 === 0) {
      setFill(doc, '#111827')
      doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
    }

    setFill(doc, p.color || '#F59E0B')
    doc.circle(MARGIN + 4, y + 3.5, 1.5, 'F')

    setText(doc, '#E5E7EB')
    doc.text(p.name.substring(0, 30), MARGIN + 8, y + 5)
    setText(doc, '#D1D5DB')
    doc.text(formatNumber(p.hours, 1), MARGIN + 60 + 30 - 2, y + 5, { align: 'right' })
    doc.text(formatCurrency(p.rate), MARGIN + 90 + 35 - 2, y + 5, { align: 'right' })
    doc.text(formatCurrency(p.earnings), MARGIN + 125 + 35 - 2, y + 5, { align: 'right' })
    setText(doc, '#9CA3AF')
    doc.text(formatNumber(p.percentage, 0) + '%', MARGIN + 160 + 20 - 2, y + 5, { align: 'right' })
    y += 7
  }

  // Totals row
  y = checkPageBreak(doc, y, 8)
  setFill(doc, '#1F2937')
  doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
  doc.setFontSize(7)
  setText(doc, '#F9FAFB')
  doc.text('Total', MARGIN + 8, y + 5)
  doc.text(formatNumber(data.totalHours, 1), MARGIN + 60 + 30 - 2, y + 5, { align: 'right' })
  doc.text(formatCurrency(data.totalEarnings), MARGIN + 125 + 35 - 2, y + 5, { align: 'right' })
}

// ---------------------------------------------------------------------------
// Profitability Report
// ---------------------------------------------------------------------------

function renderProfitabilityReport(doc: jsPDF, data: ProfitabilityReportData) {
  let y = drawHeader(doc, 'Profitability Report', data.dateRange)

  const boxW = (CONTENT_W - 8) / 5
  drawStatBox(doc, MARGIN, y, boxW, 'Revenue', formatCurrency(data.totalRevenue))
  drawStatBox(doc, MARGIN + boxW + 2, y, boxW, 'Expenses', formatCurrency(data.totalExpenses))
  drawStatBox(doc, MARGIN + (boxW + 2) * 2, y, boxW, 'Net Profit', formatCurrency(data.totalNet))
  drawStatBox(doc, MARGIN + (boxW + 2) * 3, y, boxW, 'Hours', formatNumber(data.totalHours, 1) + 'h')
  drawStatBox(doc, MARGIN + (boxW + 2) * 4, y, boxW, 'Avg Rate', formatCurrency(data.avgRate) + '/hr')
  y += 24

  const cols = [
    { label: 'Project', x: MARGIN, w: 35 },
    { label: 'Client', x: MARGIN + 35, w: 30 },
    { label: 'Hours', x: MARGIN + 65, w: 18, align: 'right' },
    { label: 'Rate', x: MARGIN + 83, w: 22, align: 'right' },
    { label: 'Revenue', x: MARGIN + 105, w: 25, align: 'right' },
    { label: 'Expenses', x: MARGIN + 130, w: 22, align: 'right' },
    { label: 'Net', x: MARGIN + 152, w: 22, align: 'right' },
    { label: 'Budget', x: MARGIN + 174, w: 16, align: 'right' },
  ]
  y = drawTableHeader(doc, y, cols)

  doc.setFontSize(6.5)
  for (let i = 0; i < data.rows.length; i++) {
    y = checkPageBreak(doc, y, 7)
    const r = data.rows[i]

    if (i % 2 === 0) {
      setFill(doc, '#111827')
      doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
    }

    setText(doc, '#E5E7EB')
    doc.text(r.project_name.substring(0, 18), MARGIN + 2, y + 5)
    setText(doc, '#D1D5DB')
    doc.text((r.client_name || '-').substring(0, 16), MARGIN + 37, y + 5)
    doc.text(formatNumber(r.total_hours, 1), MARGIN + 65 + 18 - 2, y + 5, { align: 'right' })
    doc.text(formatCurrency(r.hourly_rate), MARGIN + 83 + 22 - 2, y + 5, { align: 'right' })
    doc.text(formatCurrency(r.revenue), MARGIN + 105 + 25 - 2, y + 5, { align: 'right' })
    setText(doc, r.expenses > 0 ? '#FCA5A5' : '#D1D5DB')
    doc.text(formatCurrency(r.expenses), MARGIN + 130 + 22 - 2, y + 5, { align: 'right' })
    setText(doc, r.net_profit >= 0 ? '#86EFAC' : '#FCA5A5')
    doc.text(formatCurrency(r.net_profit), MARGIN + 152 + 22 - 2, y + 5, { align: 'right' })
    setText(doc, '#9CA3AF')
    doc.text(r.budget_used_pct != null ? formatNumber(r.budget_used_pct, 0) + '%' : '-', MARGIN + 174 + 16 - 2, y + 5, { align: 'right' })
    y += 7
  }

  // Totals row
  y = checkPageBreak(doc, y, 8)
  setFill(doc, '#1F2937')
  doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
  doc.setFontSize(6.5)
  setText(doc, '#F9FAFB')
  doc.text('Total', MARGIN + 2, y + 5)
  doc.text(formatNumber(data.totalHours, 1), MARGIN + 65 + 18 - 2, y + 5, { align: 'right' })
  doc.text(formatCurrency(data.totalRevenue), MARGIN + 105 + 25 - 2, y + 5, { align: 'right' })
  doc.text(formatCurrency(data.totalExpenses), MARGIN + 130 + 22 - 2, y + 5, { align: 'right' })
  setText(doc, data.totalNet >= 0 ? '#86EFAC' : '#FCA5A5')
  doc.text(formatCurrency(data.totalNet), MARGIN + 152 + 22 - 2, y + 5, { align: 'right' })
}

// ---------------------------------------------------------------------------
// Expenses Report
// ---------------------------------------------------------------------------

function renderExpensesReport(doc: jsPDF, data: ExpenseReportData) {
  let y = drawHeader(doc, 'Expenses Report', data.dateRange)

  const boxW = (CONTENT_W - 4) / 3
  drawStatBox(doc, MARGIN, y, boxW, 'Total', formatCurrency(data.totalAmount))
  drawStatBox(doc, MARGIN + boxW + 2, y, boxW, 'Invoiced', formatCurrency(data.invoicedAmount))
  drawStatBox(doc, MARGIN + (boxW + 2) * 2, y, boxW, 'Uninvoiced', formatCurrency(data.uninvoicedAmount))
  y += 24

  // By category
  doc.setFontSize(9)
  setText(doc, '#E5E7EB')
  doc.text('By Category', MARGIN, y + 4)
  y += 8

  const catCols = [
    { label: 'Category', x: MARGIN, w: 80 },
    { label: 'Amount', x: MARGIN + 80, w: 50, align: 'right' },
    { label: '%', x: MARGIN + 130, w: 30, align: 'right' },
  ]
  y = drawTableHeader(doc, y, catCols)

  doc.setFontSize(7)
  for (let i = 0; i < data.byCategory.length; i++) {
    y = checkPageBreak(doc, y, 7)
    const c = data.byCategory[i]
    if (i % 2 === 0) {
      setFill(doc, '#111827')
      doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
    }
    setText(doc, '#E5E7EB')
    doc.text(c.category, MARGIN + 2, y + 5)
    setText(doc, '#D1D5DB')
    doc.text(formatCurrency(c.amount), MARGIN + 80 + 50 - 2, y + 5, { align: 'right' })
    setText(doc, '#9CA3AF')
    doc.text(formatNumber(c.percentage, 0) + '%', MARGIN + 130 + 30 - 2, y + 5, { align: 'right' })
    y += 7
  }
  y += 8

  // By project
  y = checkPageBreak(doc, y, 20)
  doc.setFontSize(9)
  setText(doc, '#E5E7EB')
  doc.text('By Project', MARGIN, y + 4)
  y += 8

  const projCols = [
    { label: 'Project', x: MARGIN, w: 80 },
    { label: 'Amount', x: MARGIN + 80, w: 50, align: 'right' },
    { label: '%', x: MARGIN + 130, w: 30, align: 'right' },
  ]
  y = drawTableHeader(doc, y, projCols)

  doc.setFontSize(7)
  for (let i = 0; i < data.byProject.length; i++) {
    y = checkPageBreak(doc, y, 7)
    const p = data.byProject[i]
    if (i % 2 === 0) {
      setFill(doc, '#111827')
      doc.rect(MARGIN, y, CONTENT_W, 7, 'F')
    }
    setFill(doc, p.color || '#F59E0B')
    doc.circle(MARGIN + 4, y + 3.5, 1.5, 'F')
    setText(doc, '#E5E7EB')
    doc.text(p.name.substring(0, 30), MARGIN + 8, y + 5)
    setText(doc, '#D1D5DB')
    doc.text(formatCurrency(p.amount), MARGIN + 80 + 50 - 2, y + 5, { align: 'right' })
    setText(doc, '#9CA3AF')
    doc.text(formatNumber(p.percentage, 0) + '%', MARGIN + 130 + 30 - 2, y + 5, { align: 'right' })
    y += 7
  }
}

// ---------------------------------------------------------------------------
// Patterns Report
// ---------------------------------------------------------------------------

function renderPatternsReport(doc: jsPDF, data: PatternsReportData) {
  let y = drawHeader(doc, 'Work Patterns Report', data.dateRange)

  const boxW = (CONTENT_W - 2) / 2
  drawStatBox(doc, MARGIN, y, boxW, 'Peak Day', data.peakDay)
  drawStatBox(doc, MARGIN + boxW + 2, y, boxW, 'Peak Hour', data.peakHour)
  y += 24

  doc.setFontSize(9)
  setText(doc, '#E5E7EB')
  doc.text('Activity Heatmap', MARGIN, y + 4)
  y += 8

  const days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  const labelW = 12
  const cellW = (CONTENT_W - labelW) / 24
  const cellH = 8

  // Hour labels
  doc.setFontSize(5)
  setText(doc, '#6B7280')
  for (let h = 0; h < 24; h++) {
    if (h % 3 === 0) {
      doc.text(String(h).padStart(2, '0'), MARGIN + labelW + h * cellW + cellW / 2, y, { align: 'center' })
    }
  }
  y += 4

  const maxVal = Math.max(...data.heatmap.flat(), 0.01)

  for (let d = 0; d < 7; d++) {
    setText(doc, '#9CA3AF')
    doc.setFontSize(6)
    doc.text(days[d], MARGIN, y + cellH / 2 + 1.5)

    for (let h = 0; h < 24; h++) {
      const val = data.heatmap[d]?.[h] || 0
      const intensity = Math.min(val / maxVal, 1)
      if (intensity > 0) {
        const r = Math.round(245 * intensity + 31 * (1 - intensity))
        const g = Math.round(158 * intensity + 41 * (1 - intensity))
        const b = Math.round(11 * intensity + 55 * (1 - intensity))
        doc.setFillColor(r, g, b)
      } else {
        setFill(doc, '#1F2937')
      }
      doc.roundedRect(MARGIN + labelW + h * cellW + 0.5, y + 0.5, cellW - 1, cellH - 1, 0.5, 0.5, 'F')
    }
    y += cellH
  }
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

export function generateHoursReportPdf(data: HoursReportData): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  setFill(doc, '#0D1117')
  doc.rect(0, 0, PAGE_W, PAGE_H, 'F')
  renderHoursReport(doc, data)
  return doc
}

export function generateProfitabilityReportPdf(data: ProfitabilityReportData): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  setFill(doc, '#0D1117')
  doc.rect(0, 0, PAGE_W, PAGE_H, 'F')
  renderProfitabilityReport(doc, data)
  return doc
}

export function generateExpensesReportPdf(data: ExpenseReportData): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  setFill(doc, '#0D1117')
  doc.rect(0, 0, PAGE_W, PAGE_H, 'F')
  renderExpensesReport(doc, data)
  return doc
}

export function generatePatternsReportPdf(data: PatternsReportData): jsPDF {
  const doc = new jsPDF({ unit: 'mm', format: 'a4' })
  setFill(doc, '#0D1117')
  doc.rect(0, 0, PAGE_W, PAGE_H, 'F')
  renderPatternsReport(doc, data)
  return doc
}
