'use client'

import { useState, useCallback } from 'react'
import { Modal, Button, Checkbox, Input, Select } from '@ciphera-net/ui'
import * as XLSX from 'xlsx'
import jsPDF from 'jspdf'
import autoTable from 'jspdf-autotable'
import type { DailyStat } from './Chart'
import { formatNumber, formatDuration } from '@ciphera-net/ui'
import { formatDateISO, formatDate, formatDateTime } from '@/lib/utils/formatDate'
import { getReferrerDisplayName, mergeReferrersByDisplayName } from '@/lib/utils/icons'
import type { TopPage, TopReferrer, CampaignStat } from '@/lib/api/stats'

interface ExportModalProps {
  isOpen: boolean
  onClose: () => void
  data: DailyStat[]
  stats?: {
    pageviews: number
    visitors: number
    bounce_rate: number
    avg_duration: number
  }
  topPages?: TopPage[]
  topReferrers?: TopReferrer[]
  campaigns?: CampaignStat[]
}

type ExportFormat = 'csv' | 'json' | 'xlsx' | 'pdf'

const loadImage = (src: string): Promise<string> => {
  return new Promise((resolve, reject) => {
    const img = new Image()
    img.crossOrigin = 'Anonymous'
    img.onload = () => {
      const canvas = document.createElement('canvas')
      canvas.width = img.width
      canvas.height = img.height
      const ctx = canvas.getContext('2d')
      if (!ctx) return reject('Could not get canvas context')
      ctx.drawImage(img, 0, 0)
      resolve(canvas.toDataURL('image/png'))
    }
    img.onerror = reject
    img.src = src
  })
}

export default function ExportModal({ isOpen, onClose, data, stats, topPages, topReferrers, campaigns }: ExportModalProps) {
  const [format, setFormat] = useState<ExportFormat>('csv')
  const [filename, setFilename] = useState(`pulse_export_${formatDateISO(new Date())}`)
  const [includeHeader, setIncludeHeader] = useState(true)
  const [isExporting, setIsExporting] = useState(false)
  const [exportDone, setExportDone] = useState(false)
  const [exportProgress, setExportProgress] = useState({ step: 0, total: 1, label: '' })
  const [selectedFields, setSelectedFields] = useState<Record<keyof DailyStat, boolean>>({
    date: true,
    pageviews: true,
    visitors: true,
    bounce_rate: true,
    avg_duration: true,
  })

  const handleFieldChange = (field: keyof DailyStat, checked: boolean) => {
    setSelectedFields((prev) => ({ ...prev, [field]: checked }))
  }

  const finishExport = useCallback(() => {
    setExportDone(true)
    setIsExporting(false)
    setTimeout(() => {
      setExportDone(false)
      onClose()
    }, 600)
  }, [onClose])

  // Yield to the UI thread so the browser can paint progress updates
  const updateProgress = useCallback(async (step: number, total: number, label: string) => {
    setExportProgress({ step, total, label })
    await new Promise(resolve => setTimeout(resolve, 0))
  }, [])

  const handleExport = () => {
    setIsExporting(true)
    setExportProgress({ step: 0, total: 1, label: 'Preparing...' })
    // Let the browser paint the loading state before starting heavy work
    requestAnimationFrame(() => {
      setTimeout(async () => {
        try {
          // Filter fields
          const fields = (Object.keys(selectedFields) as Array<keyof DailyStat>).filter((k) => selectedFields[k])

          // Prepare data
          const exportData = data.map((item) => {
            const filteredItem: Record<string, string | number> = {}
            fields.forEach((field) => {
              filteredItem[field] = item[field]
            })
            return filteredItem
          })

          let content = ''
          let mimeType = ''
          let extension = ''

          if (format === 'csv') {
            const header = fields.join(',')
            const rows = exportData.map((row) =>
              fields.map((field) => {
                  const val = row[field]
                  if (field === 'date' && typeof val === 'string') {
                       return new Date(val).toISOString()
                  }
                  return val
              }).join(',')
            )
            content = (includeHeader ? header + '\n' : '') + rows.join('\n')
            mimeType = 'text/csv;charset=utf-8;'
            extension = 'csv'
          } else if (format === 'xlsx') {
            await updateProgress(1, 2, 'Building spreadsheet...')
            const ws = XLSX.utils.json_to_sheet(exportData)
            const wb = XLSX.utils.book_new()
            XLSX.utils.book_append_sheet(wb, ws, 'Data')
            if (campaigns && campaigns.length > 0) {
              const campaignsSheet = XLSX.utils.json_to_sheet(
                campaigns.map(c => ({
                  Source: getReferrerDisplayName(c.source),
                  Medium: c.medium || '—',
                  Campaign: c.campaign || '—',
                  Visitors: c.visitors,
                  Pageviews: c.pageviews,
                }))
              )
              XLSX.utils.book_append_sheet(wb, campaignsSheet, 'Campaigns')
            }
            const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' })
            const blob = new Blob([wbout], { type: 'application/octet-stream' })

            const url = URL.createObjectURL(blob)
            const link = document.createElement('a')
            link.setAttribute('href', url)
            link.setAttribute('download', `${filename || 'export'}.${extension || 'xlsx'}`)
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
            finishExport()
            return
          } else if (format === 'pdf') {
            const totalSteps = 3 + (topPages?.length ? 1 : 0) + (topReferrers?.length ? 1 : 0) + (campaigns?.length ? 1 : 0)
            let currentStep = 0
            const doc = new jsPDF()

            // Header Section
            await updateProgress(++currentStep, totalSteps, 'Building header...')
            try {
              // Logo
              const logoData = await loadImage('/pulse_icon_no_margins.png')
              doc.addImage(logoData, 'PNG', 14, 12, 12, 12) // x, y, w, h

              // Title
              doc.setFontSize(22)
              doc.setTextColor(249, 115, 22) // Brand Orange #F97316
              doc.text('Pulse', 32, 20)

              doc.setFontSize(12)
              doc.setTextColor(100, 100, 100)
              doc.text('Analytics Export', 32, 25)
            } catch (e) {
              // Fallback if logo fails
              doc.setFontSize(22)
              doc.setTextColor(249, 115, 22)
              doc.text('Pulse Analytics', 14, 20)
            }

            // Metadata (Top Right)
            doc.setFontSize(9)
            doc.setTextColor(150, 150, 150)
            const generatedDate = formatDate(new Date())
            const dateRange = data.length > 0
              ? `${formatDate(new Date(data[0].date))} - ${formatDate(new Date(data[data.length - 1].date))}`
              : generatedDate

            const pageWidth = doc.internal.pageSize.width
            doc.text(`Generated: ${generatedDate}`, pageWidth - 14, 18, { align: 'right' })
            doc.text(`Range: ${dateRange}`, pageWidth - 14, 23, { align: 'right' })

            let startY = 35

            // Summary Section
            if (stats) {
              const summaryY = 35
              const cardWidth = (pageWidth - 28 - 15) / 4 // 4 cards with 5mm gap
              const cardHeight = 20

              const drawCard = (x: number, label: string, value: string) => {
                  doc.setFillColor(255, 247, 237) // Very light orange
                  doc.setDrawColor(254, 215, 170) // Light orange border
                  doc.roundedRect(x, summaryY, cardWidth, cardHeight, 2, 2, 'FD')

                  doc.setFontSize(8)
                  doc.setTextColor(150, 150, 150)
                  doc.text(label, x + 3, summaryY + 6)

                  doc.setFontSize(12)
                  doc.setTextColor(23, 23, 23) // Neutral 900
                  doc.setFont('helvetica', 'bold')
                  doc.text(value, x + 3, summaryY + 14)
                  doc.setFont('helvetica', 'normal')
              }

              drawCard(14, 'Unique Visitors', formatNumber(stats.visitors))
              drawCard(14 + cardWidth + 5, 'Total Pageviews', formatNumber(stats.pageviews))
              drawCard(14 + (cardWidth + 5) * 2, 'Bounce Rate', `${Math.round(stats.bounce_rate)}%`)
              drawCard(14 + (cardWidth + 5) * 3, 'Avg Duration', formatDuration(stats.avg_duration))

              startY = 65 // Move table down
            }

            await updateProgress(++currentStep, totalSteps, 'Generating data table...')
            // Check if data is hourly (same date for multiple rows)
            const isHourly = data.length > 1 && data[0].date.split('T')[0] === data[1].date.split('T')[0]

            const tableData = exportData.map(row =>
              fields.map(field => {
                const val = row[field]
                if (field === 'date' && typeof val === 'string') {
                  const date = new Date(val)
                  return isHourly ? formatDateTime(date) : formatDate(date)
                }
                if (typeof val === 'number') {
                   if (field === 'bounce_rate') return `${Math.round(val)}%`
                   if (field === 'avg_duration') return formatDuration(val)
                   if (field === 'pageviews' || field === 'visitors') return formatNumber(val)
                }
                return val ?? ''
              })
            )

            autoTable(doc, {
              startY: startY,
              head: [fields.map(f => f.charAt(0).toUpperCase() + f.slice(1).replace('_', ' '))],
              body: tableData as (string | number)[][],
              styles: {
                  font: 'helvetica',
                  fontSize: 9,
                  cellPadding: 4,
                  lineColor: [229, 231, 235], // Neutral 200
                  lineWidth: 0.1,
              },
              headStyles: {
                  fillColor: [249, 115, 22], // Brand Orange
                  textColor: [255, 255, 255],
                  fontStyle: 'bold',
                  halign: 'left'
              },
              columnStyles: {
                  0: { halign: 'left' }, // Date
                  1: { halign: 'right' }, // Pageviews
                  2: { halign: 'right' }, // Visitors
                  3: { halign: 'right' }, // Bounce Rate
                  4: { halign: 'right' }, // Avg Duration
              },
              alternateRowStyles: {
                  fillColor: [255, 250, 245], // Very very light orange
              },
              didDrawPage: (data) => {
                  // Footer
                  const pageSize = doc.internal.pageSize
                  const pageHeight = pageSize.height ? pageSize.height : pageSize.getHeight()
                  doc.setFontSize(8)
                  doc.setTextColor(150, 150, 150)
                  doc.text('Powered by Ciphera', 14, pageHeight - 10)

                  const str = 'Page ' + doc.getNumberOfPages()
                  doc.text(str, pageSize.width - 14, pageHeight - 10, { align: 'right' })
              }
            })

            let finalY = doc.lastAutoTable.finalY + 10

            // Top Pages Table
            if (topPages && topPages.length > 0) {
              await updateProgress(++currentStep, totalSteps, 'Adding top pages...')
              // Check if we need a new page
              if (finalY + 40 > doc.internal.pageSize.height) {
                  doc.addPage()
                  finalY = 20
              }

              doc.setFontSize(14)
              doc.setTextColor(23, 23, 23)
              doc.text('Top Pages', 14, finalY)
              finalY += 5

              const pagesData = topPages.slice(0, 10).map(p => [p.path, formatNumber(p.pageviews)])

              autoTable(doc, {
                  startY: finalY,
                  head: [['Path', 'Pageviews']],
                  body: pagesData,
                  styles: { font: 'helvetica', fontSize: 9, cellPadding: 3 },
                  headStyles: { fillColor: [249, 115, 22], textColor: [255, 255, 255], fontStyle: 'bold' },
                  columnStyles: { 1: { halign: 'right' } },
                  alternateRowStyles: { fillColor: [255, 250, 245] },
              })

              finalY = doc.lastAutoTable.finalY + 10
            }

            // Top Referrers Table
            if (topReferrers && topReferrers.length > 0) {
              await updateProgress(++currentStep, totalSteps, 'Adding top referrers...')
               // Check if we need a new page
               if (finalY + 40 > doc.internal.pageSize.height) {
                  doc.addPage()
                  finalY = 20
              }

              doc.setFontSize(14)
              doc.setTextColor(23, 23, 23)
              doc.text('Top Referrers', 14, finalY)
              finalY += 5

              const mergedReferrers = mergeReferrersByDisplayName(topReferrers)
              const referrersData = mergedReferrers.slice(0, 10).map(r => [getReferrerDisplayName(r.referrer), formatNumber(r.pageviews)])

              autoTable(doc, {
                  startY: finalY,
                  head: [['Referrer', 'Pageviews']],
                  body: referrersData,
                  styles: { font: 'helvetica', fontSize: 9, cellPadding: 3 },
                  headStyles: { fillColor: [249, 115, 22], textColor: [255, 255, 255], fontStyle: 'bold' },
                  columnStyles: { 1: { halign: 'right' } },
                  alternateRowStyles: { fillColor: [255, 250, 245] },
              })

              finalY = doc.lastAutoTable.finalY + 10
            }

            // Campaigns Table
            if (campaigns && campaigns.length > 0) {
              await updateProgress(++currentStep, totalSteps, 'Adding campaigns...')
              if (finalY + 40 > doc.internal.pageSize.height) {
                doc.addPage()
                finalY = 20
              }
              doc.setFontSize(14)
              doc.setTextColor(23, 23, 23)
              doc.text('Campaigns', 14, finalY)
              finalY += 5
              const campaignsData = campaigns.slice(0, 10).map(c => [
                getReferrerDisplayName(c.source),
                c.medium || '—',
                c.campaign || '—',
                formatNumber(c.visitors),
                formatNumber(c.pageviews),
              ])
              autoTable(doc, {
                startY: finalY,
                head: [['Source', 'Medium', 'Campaign', 'Visitors', 'Pageviews']],
                body: campaignsData,
                styles: { font: 'helvetica', fontSize: 9, cellPadding: 3 },
                headStyles: { fillColor: [249, 115, 22], textColor: [255, 255, 255], fontStyle: 'bold' },
                columnStyles: { 3: { halign: 'right' }, 4: { halign: 'right' } },
                alternateRowStyles: { fillColor: [255, 250, 245] },
              })
            }

            await updateProgress(totalSteps, totalSteps, 'Saving PDF...')
            doc.save(`${filename || 'export'}.pdf`)
            finishExport()
            return
          } else {
            content = JSON.stringify(exportData, null, 2)
            mimeType = 'application/json;charset=utf-8;'
            extension = 'json'
          }

          const blob = new Blob([content], { type: mimeType })
          const url = URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.setAttribute('href', url)
          link.setAttribute('download', `${filename || 'export'}.${extension}`)
          document.body.appendChild(link)
          link.click()
          document.body.removeChild(link)

          finishExport()
        } catch (e) {
          console.error('Export failed:', e)
        } finally {
          setIsExporting(false)
        }
      }, 0)
    })
  }

  return (
    <Modal isOpen={isOpen} onClose={onClose} title="Export Data">
      <div className="space-y-6">
        {/* Filename & Format */}
        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
          <div className="space-y-2">
            <label htmlFor="filename" className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
              Filename
            </label>
            <Input
              id="filename"
              value={filename}
              onChange={(e) => setFilename(e.target.value)}
              placeholder="filename"
            />
          </div>
          <div className="space-y-2">
            <label htmlFor="format" className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
              Format
            </label>
            <Select
              id="format"
              value={format}
              onChange={(val) => setFormat(val as ExportFormat)}
              options={[
                { value: 'csv', label: 'CSV' },
                { value: 'json', label: 'JSON' },
                { value: 'xlsx', label: 'Excel' },
                { value: 'pdf', label: 'PDF' },
              ]}
              variant="input"
              fullWidth
            />
          </div>
        </div>

        {/* Fields Selection */}
        <div className="space-y-3">
          <label className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
            Include Fields
          </label>
          <div className="grid grid-cols-2 gap-3">
            <Checkbox
              checked={selectedFields.date}
              onCheckedChange={(c) => handleFieldChange('date', c)}
              label="Date"
            />
            <Checkbox
              checked={selectedFields.pageviews}
              onCheckedChange={(c) => handleFieldChange('pageviews', c)}
              label="Pageviews"
            />
            <Checkbox
              checked={selectedFields.visitors}
              onCheckedChange={(c) => handleFieldChange('visitors', c)}
              label="Visitors"
            />
            <Checkbox
              checked={selectedFields.bounce_rate}
              onCheckedChange={(c) => handleFieldChange('bounce_rate', c)}
              label="Bounce Rate"
            />
            <Checkbox
              checked={selectedFields.avg_duration}
              onCheckedChange={(c) => handleFieldChange('avg_duration', c)}
              label="Avg Duration"
            />
          </div>
        </div>

        {/* Additional Options */}
        {format === 'csv' && (
          <div className="pt-2 border-t border-neutral-100 dark:border-neutral-800">
             <Checkbox
              checked={includeHeader}
              onCheckedChange={setIncludeHeader}
              label="Include Header Row"
            />
          </div>
        )}

        {/* Progress Bar */}
        {(isExporting || exportDone) && (
          <div className="space-y-2 pt-2">
            <div className="flex items-center justify-between text-xs text-neutral-500 dark:text-neutral-400">
              <span>{exportDone ? 'Export complete' : exportProgress.label}</span>
              <span>{exportDone ? '100%' : `${Math.round((exportProgress.step / exportProgress.total) * 100)}%`}</span>
            </div>
            <div className="h-1.5 w-full rounded-full bg-neutral-100 dark:bg-neutral-800 overflow-hidden">
              <div
                className={`h-full rounded-full transition-all duration-300 ease-out ${exportDone ? 'bg-green-500' : 'bg-brand-orange'}`}
                style={{ width: exportDone ? '100%' : `${(exportProgress.step / exportProgress.total) * 100}%` }}
              />
            </div>
          </div>
        )}

        {/* Actions */}
        <div className="flex justify-end gap-3 pt-4">
          <Button variant="secondary" onClick={onClose} disabled={isExporting}>
            Cancel
          </Button>
          <Button variant="primary" onClick={handleExport} disabled={isExporting || exportDone}>
            {exportDone ? '✓ Done' : isExporting ? 'Exporting...' : 'Export Data'}
          </Button>
        </div>
      </div>
    </Modal>
  )
}
