import { useEffect, useState, useCallback } from 'react'
import { useSearchParams } from 'react-router-dom'
import { Plus, Ticket, AlertTriangle } from 'lucide-react'
import axios from 'axios'
import { TicketFilterBar } from '@/components/tickets/TicketFilterBar'
import { TicketListRow } from '@/components/tickets/TicketListRow'
import { TicketDetailPanel } from '@/components/tickets/TicketDetailPanel'
import { NewTicketModal } from '@/components/tickets/NewTicketModal'
import { integrationsApi } from '@/api/integrations'
import { ticketsApi } from '@/api/tickets'
import type { PSATicketSearchResult, PSABoard, PSATicketStatusItem } from '@/types/integrations'
import type { TicketFilters, PSAPriority } from '@/types/tickets'
import { DEFAULT_TICKET_FILTERS } from '@/types/tickets'

const PAGE_SIZE = 25

function filtersFromParams(params: URLSearchParams): TicketFilters & { page: number } {
  const assigned = params.get('assigned') ?? 'all'
  return {
    ...DEFAULT_TICKET_FILTERS,
    search: params.get('search') ?? '',
    board_id: params.get('board') ? Number(params.get('board')) : null,
    status_id: params.get('status') ? Number(params.get('status')) : null,
    priority: params.get('priority') ?? null,
    company_id: params.get('company') ? Number(params.get('company')) : null,
    assigned: (assigned === 'me' || assigned === 'unassigned' || assigned === 'all')
      ? assigned
      : Number(assigned),
    include_closed: params.get('closed') === 'true',
    page: params.get('page') ? Number(params.get('page')) : 1,
  }
}

export default function TicketsPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const { page, ...filters } = filtersFromParams(searchParams)

  const [tickets, setTickets] = useState<PSATicketSearchResult[]>([])
  const [total, setTotal] = useState(0)
  const [loading, setLoading] = useState(false)
  const [psaError, setPsaError] = useState<string | null>(null)
  const [boards, setBoards] = useState<PSABoard[]>([])
  const [statuses, setStatuses] = useState<PSATicketStatusItem[]>([])
  const [priorities, setPriorities] = useState<PSAPriority[]>([])
  const [members, setMembers] = useState<{ id: number; name: string }[]>([])
  const [selectedTicket, setSelectedTicket] = useState<PSATicketSearchResult | null>(null)
  const [showNewTicket, setShowNewTicket] = useState(false)

  // Load filter option data once
  useEffect(() => {
    integrationsApi.listBoards().then(setBoards).catch(() => {})
    ticketsApi.listPriorities().then(setPriorities).catch(() => {})
    integrationsApi.listMembers()
      .then(ms => setMembers(ms.map(m => ({ id: Number(m.id), name: m.name }))))
      .catch(() => {})
  }, [])

  // Load statuses when board changes. If no board is selected, aggregate statuses
  // across all boards (deduped by name) so the filter is useful before the user
  // picks a board.
  useEffect(() => {
    let cancelled = false
    if (filters.board_id) {
      integrationsApi.getBoardStatuses(filters.board_id)
        .then(s => { if (!cancelled) setStatuses(s) })
        .catch(() => { if (!cancelled) setStatuses([]) })
    } else if (boards.length > 0) {
      Promise.all(boards.map(b =>
        integrationsApi.getBoardStatuses(b.id).catch(() => [] as PSATicketStatusItem[])
      ))
        .then(lists => {
          if (cancelled) return
          const byName = new Map<string, PSATicketStatusItem>()
          lists.flat().forEach(s => {
            if (!byName.has(s.name)) byName.set(s.name, s)
          })
          setStatuses(Array.from(byName.values()).sort((a, b) => a.name.localeCompare(b.name)))
        })
        .catch(() => { if (!cancelled) setStatuses([]) })
    } else {
      setStatuses([])
    }
    return () => { cancelled = true }
  }, [filters.board_id, boards])

  // Fetch tickets on filter/page change
  const fetchTickets = useCallback(async () => {
    setLoading(true)
    setPsaError(null)
    try {
      // When no board is selected, statuses are aggregated across boards — filter by
      // name instead of id so we match the same status across every board.
      const selectedStatusName = filters.status_id
        ? statuses.find(s => s.id === filters.status_id)?.name
        : undefined
      const result = await ticketsApi.searchTickets({
        query: filters.search || undefined,
        board_id: filters.board_id ?? undefined,
        status_id: filters.board_id && filters.status_id ? filters.status_id : undefined,
        status_name: !filters.board_id && selectedStatusName ? selectedStatusName : undefined,
        include_closed: filters.include_closed,
        assigned_to_me: filters.assigned === 'me',
        unassigned: filters.assigned === 'unassigned',
        priority: filters.priority ?? undefined,
        company_id: filters.company_id ?? undefined,
        page,
        page_size: PAGE_SIZE,
      })
      setTickets(result.items)
      setTotal(result.total)
      // If the boards API returned empty (CW permissions), derive available boards from ticket data
      setBoards(prev => {
        if (prev.length > 0) return prev
        const seen = new Map<number, string>()
        result.items.forEach(t => {
          if (t.board_id && t.board_name) seen.set(t.board_id, t.board_name)
        })
        return seen.size > 0 ? Array.from(seen, ([id, name]) => ({ id, name })) : prev
      })
    } catch (err: unknown) {
      setTickets([])
      setTotal(0)
      if (axios.isAxiosError(err)) {
        const status = err.response?.status
        const detail = (err.response?.data as { detail?: string })?.detail ?? ''
        if (status === 502 && detail.toLowerCase().includes('permission')) {
          setPsaError('ConnectWise returned a permissions error. Check that the API member\'s security role has Service Tickets → Inquire → ALL and System → Table Setup → Inquire → ALL.')
        } else if (status === 502) {
          setPsaError('ConnectWise is unavailable or returned an error. Check your integration settings.')
        } else {
          setPsaError('Failed to load tickets.')
        }
      }
    } finally {
      setLoading(false)
    }
  }, [filters.search, filters.board_id, filters.status_id, filters.include_closed,
      filters.assigned, filters.priority, filters.company_id, page, statuses])

  useEffect(() => { fetchTickets() }, [fetchTickets])

  function updateFilters(updated: Partial<TicketFilters>) {
    const next = new URLSearchParams(searchParams)
    if ('search' in updated) updated.search ? next.set('search', updated.search!) : next.delete('search')
    if ('board_id' in updated) updated.board_id ? next.set('board', String(updated.board_id)) : next.delete('board')
    if ('status_id' in updated) updated.status_id ? next.set('status', String(updated.status_id)) : next.delete('status')
    if ('priority' in updated) updated.priority ? next.set('priority', updated.priority!) : next.delete('priority')
    if ('company_id' in updated) updated.company_id ? next.set('company', String(updated.company_id)) : next.delete('company')
    if ('assigned' in updated) {
      const a = updated.assigned
      a === 'all' ? next.delete('assigned') : next.set('assigned', String(a))
    }
    if ('include_closed' in updated) updated.include_closed ? next.set('closed', 'true') : next.delete('closed')
    next.delete('page') // reset to 1 on filter change
    setSearchParams(next)
  }

  function updatePage(p: number) {
    const next = new URLSearchParams(searchParams)
    p === 1 ? next.delete('page') : next.set('page', String(p))
    setSearchParams(next)
  }

  return (
    <div className="flex flex-col h-full overflow-hidden">
      {/* Header */}
      <div className="flex items-center justify-between px-6 py-4 border-b border-default shrink-0">
        <div className="flex items-center gap-2">
          <Ticket className="w-5 h-5 text-muted-foreground" />
          <h1 className="font-heading text-xl font-bold text-heading">Tickets</h1>
        </div>
        <button
          onClick={() => setShowNewTicket(true)}
          className="flex items-center gap-1.5 px-3 py-1.5 bg-accent text-white text-sm font-medium rounded-[5px] hover:bg-accent/90 transition-colors"
        >
          <Plus className="w-4 h-4" /> New Ticket
        </button>
      </div>

      {/* Filters */}
      <div className="px-6 py-3 border-b border-default shrink-0">
        <TicketFilterBar
          filters={filters}
          onChange={updateFilters}
          boards={boards}
          statuses={statuses}
          priorities={priorities}
          members={members}
          total={total}
          page={page}
          pageSize={PAGE_SIZE}
          onPageChange={updatePage}
          loading={loading}
        />
      </div>

      {/* List + Detail Panel */}
      <div className="flex flex-1 overflow-hidden">
        {/* Ticket list */}
        <div className={`flex flex-col overflow-y-auto transition-all ${selectedTicket ? 'w-1/2' : 'w-full'}`}>
          {loading && tickets.length === 0 && (
            <div className="flex items-center justify-center py-16 text-muted-foreground text-sm">
              Loading tickets…
            </div>
          )}
          {!loading && psaError && (
            <div className="mx-6 mt-6 flex items-start gap-3 px-4 py-3 rounded-lg bg-danger-dim border border-danger/30 text-sm text-danger">
              <AlertTriangle className="w-4 h-4 mt-0.5 shrink-0" />
              <span>{psaError}</span>
            </div>
          )}
          {!loading && !psaError && tickets.length === 0 && (
            <div className="flex flex-col items-center justify-center py-16 text-muted-foreground text-sm gap-2">
              <Ticket className="w-8 h-8 opacity-30" />
              No tickets match your filters
            </div>
          )}
          {tickets.map(t => (
            <TicketListRow
              key={t.id}
              ticket={t}
              selected={selectedTicket?.id === t.id}
              onClick={() => setSelectedTicket(t)}
            />
          ))}
        </div>

        {/* Detail panel */}
        {selectedTicket && (
          <div className="w-1/2 border-l border-default overflow-y-auto">
            <TicketDetailPanel
              ticket={selectedTicket}
              onClose={() => setSelectedTicket(null)}
              onStatusUpdated={(ticketId, newStatus, newStatusId) => {
                setTickets(prev => prev.map(t =>
                  t.id === String(ticketId) ? { ...t, status_name: newStatus, status_id: newStatusId } : t
                ))
                setSelectedTicket(prev =>
                  prev && prev.id === String(ticketId)
                    ? { ...prev, status_name: newStatus, status_id: newStatusId }
                    : prev
                )
              }}
            />
          </div>
        )}
      </div>

      {/* New Ticket Modal */}
      {showNewTicket && (
        <NewTicketModal
          defaultTab="quick"
          onClose={() => setShowNewTicket(false)}
          onCreated={() => { setShowNewTicket(false); fetchTickets() }}
        />
      )}
    </div>
  )
}
