import { useState, useMemo, useCallback } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import { AppLayout } from '../../components/layout/AppLayout';
import { LoadingSpinner } from '../../components/ui/LoadingSpinner';
import {
  estimatesApi,
  type Estimate,
  type EstimateStage,
  type EstimateSource,
} from '../../api/estimates';
import {
  Search,
  Filter,
  X,
  ChevronDown,
  ChevronUp,
  ChevronsUpDown,
  ArrowRight,
  FileText,
  MoreVertical,
  RotateCcw,
} from 'lucide-react';

// ─── Helpers ──────────────────────────────────────────────────────────────

function formatCurrency(value: number): string {
  if (value >= 1_000_000) return `$${(value / 1_000_000).toFixed(1)}M`;
  if (value >= 1_000) return `$${(value / 1_000).toFixed(1)}K`;
  return `$${value.toFixed(0)}`;
}

function formatDate(dateStr: string): string {
  return new Date(dateStr).toLocaleDateString('en-US', {
    month: 'short',
    day: 'numeric',
    year: 'numeric',
  });
}

function capitalize(str: string): string {
  return str.charAt(0).toUpperCase() + str.slice(1);
}

function capitalizeSource(src: EstimateSource): string {
  const map: Record<EstimateSource, string> = {
    manual: 'Manual',
    angi: 'Angi',
    servicetitan: 'ServiceTitan',
    jobber: 'Jobber',
    hubspot: 'HubSpot',
    email: 'Email',
    referral: 'Referral',
    website: 'Website',
  };
  return map[src] ?? capitalize(src);
}

// ─── Stage badge colors ───────────────────────────────────────────────────

const STAGE_BADGES: Record<EstimateStage, { bg: string; text: string; label: string }> = {
  draft:      { bg: 'bg-slate-100',   text: 'text-slate-700',   label: 'Draft' },
  delivered:  { bg: 'bg-blue-100',    text: 'text-blue-700',    label: 'Delivered' },
  accepted:   { bg: 'bg-emerald-100', text: 'text-emerald-700', label: 'Accepted' },
  scheduled:  { bg: 'bg-amber-100',   text: 'text-amber-700',   label: 'Scheduled' },
  closed:     { bg: 'bg-green-100',   text: 'text-green-700',   label: 'Closed' },
  rejected:   { bg: 'bg-red-100',     text: 'text-red-700',     label: 'Rejected' },
  expired:    { bg: 'bg-gray-100',    text: 'text-gray-700',    label: 'Expired' },
};

// ─── Valid stage transitions ─────────────────────────────────────────────

const VALID_TRANSITIONS: Record<EstimateStage, EstimateStage[]> = {
  draft:     ['delivered'],
  delivered: ['accepted', 'rejected', 'expired'],
  accepted:  ['scheduled', 'rejected'],
  scheduled: ['closed', 'rejected'],
  rejected:  [],
  expired:   [],
  closed:    [],
};

// ─── Sort config ──────────────────────────────────────────────────────────

type SortField = 'estimate_number' | 'customer_name' | 'project_type' | 'total_value' | 'stage' | 'source' | 'created_at';
type SortOrder = 'asc' | 'desc';

interface SortState {
  field: SortField;
  order: SortOrder;
}

const DEFAULT_SORT: SortState = { field: 'created_at', order: 'desc' };

const SORTABLE_COLUMNS: { key: SortField; label: string }[] = [
  { key: 'estimate_number', label: 'Estimate #' },
  { key: 'customer_name', label: 'Customer' },
  { key: 'project_type', label: 'Project Type' },
  { key: 'total_value', label: 'Value' },
  { key: 'stage', label: 'Stage' },
  { key: 'source', label: 'Source' },
  { key: 'created_at', label: 'Created' },
];

// ─── Filter types ─────────────────────────────────────────────────────────

interface Filters {
  stage: EstimateStage | '';
  source: EstimateSource | '';
  minValue: string;
  maxValue: string;
  search: string;
}

const DEFAULT_FILTERS: Filters = {
  stage: '',
  source: '',
  minValue: '',
  maxValue: '',
  search: '',
};

const ALL_STAGES: { value: EstimateStage; label: string }[] = [
  { value: 'draft', label: 'Draft' },
  { value: 'delivered', label: 'Delivered' },
  { value: 'accepted', label: 'Accepted' },
  { value: 'scheduled', label: 'Scheduled' },
  { value: 'closed', label: 'Closed' },
  { value: 'rejected', label: 'Rejected' },
  { value: 'expired', label: 'Expired' },
];

const ALL_SOURCES: { value: EstimateSource; label: string }[] = [
  { value: 'manual', label: 'Manual' },
  { value: 'angi', label: 'Angi' },
  { value: 'servicetitan', label: 'ServiceTitan' },
  { value: 'jobber', label: 'Jobber' },
  { value: 'hubspot', label: 'HubSpot' },
  { value: 'email', label: 'Email' },
  { value: 'referral', label: 'Referral' },
  { value: 'website', label: 'Website' },
];

// ─── Stage Badge with inline transition ───────────────────────────────────

function StageTransitionBadge({
  estimate,
  onTransition,
  transitioning,
}: {
  estimate: Estimate;
  onTransition: (_id: string, _stage: EstimateStage) => void;
  transitioning: boolean;
}) {
  const [open, setOpen] = useState(false);
  const badge = STAGE_BADGES[estimate.stage];
  const options = VALID_TRANSITIONS[estimate.stage];

  if (options.length === 0) {
    return (
      <span
        className={`inline-flex rounded-full px-2.5 py-1 text-xs font-semibold ${badge.bg} ${badge.text} cursor-default`}
        title={`${badge.label} (terminal)`}
      >
        {badge.label}
      </span>
    );
  }

  return (
    <div className="relative inline-block">
      <button
        onClick={() => setOpen(!open)}
        className={`inline-flex items-center gap-1 rounded-full px-2.5 py-1 text-xs font-semibold ${badge.bg} ${badge.text} hover:opacity-80 cursor-pointer min-h-[28px]`}
        title="Click to transition stage"
      >
        {badge.label}
        <ChevronDown className="h-3 w-3 opacity-60" />
      </button>

      {open && (
        <>
          <div className="fixed inset-0 z-40" onClick={() => setOpen(false)} />
          <div className="absolute left-0 top-full mt-1 z-50 w-48 rounded-lg border border-surface-200 bg-white shadow-lg py-1">
            <p className="px-3 py-1.5 text-[10px] font-semibold uppercase tracking-wider text-surface-400">
              Move to…
            </p>
            {options.map((nextStage) => {
              const next = STAGE_BADGES[nextStage];
              return (
                <button
                  key={nextStage}
                  disabled={transitioning}
                  onClick={() => {
                    onTransition(estimate.id, nextStage);
                    setOpen(false);
                  }}
                  className="w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-surface-50 disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  <span className={`inline-flex rounded-full px-2 py-0.5 text-[10px] font-semibold ${next.bg} ${next.text}`}>
                    {next.label}
                  </span>
                  <ArrowRight className="h-3 w-3 text-surface-400" />
                </button>
              );
            })}
          </div>
        </>
      )}
    </div>
  );
}

// ─── Pagination ───────────────────────────────────────────────────────────

function Pagination({
  page,
  perPage,
  total,
  totalPages,
  onPageChange,
}: {
  page: number;
  perPage: number;
  total: number;
  totalPages: number;
  onPageChange: (page: number) => void;
}) {
  const totalPagesClamped = Math.max(totalPages, 1);

  const getPageNumbers = (): (number | string)[] => {
    const pages: (number | string)[] = [];
    if (totalPagesClamped <= 7) {
      for (let i = 1; i <= totalPagesClamped; i++) pages.push(i);
    } else {
      pages.push(1);
      if (page > 3) pages.push('…');
      for (let i = Math.max(2, page - 1); i <= Math.min(totalPagesClamped - 1, page + 1); i++) {
        pages.push(i);
      }
      if (page < totalPagesClamped - 2) pages.push('…');
      pages.push(totalPagesClamped);
    }
    return pages;
  };

  const startItem = (page - 1) * perPage + 1;
  const endItem = Math.min(page * perPage, total);

  return (
    <div className="flex flex-col sm:flex-row items-center justify-between gap-4 px-4 py-3 border-t border-surface-200">
      <p className="text-sm text-surface-500">
        Showing <span className="font-medium text-surface-700">{startItem}</span> to{' '}
        <span className="font-medium text-surface-700">{total > 0 ? endItem : 0}</span> of{' '}
        <span className="font-medium text-surface-700">{total}</span> estimates
      </p>

      {totalPagesClamped > 1 && (
        <div className="flex items-center gap-1">
          <button
            onClick={() => onPageChange(page - 1)}
            disabled={page <= 1}
            className="inline-flex items-center justify-center w-8 h-8 rounded-md border border-surface-300 text-sm text-surface-600 hover:bg-surface-50 disabled:opacity-40 disabled:cursor-not-allowed"
            title="Previous page"
          >
            ‹
          </button>

          {getPageNumbers().map((p, i) =>
            typeof p === 'string' ? (
              <span key={`ellipsis-${i}`} className="w-8 h-8 flex items-center justify-center text-surface-400 text-sm">
                {p}
              </span>
            ) : (
              <button
                key={p}
                onClick={() => onPageChange(p)}
                className={`inline-flex items-center justify-center w-8 h-8 rounded-md text-sm font-medium ${
                  p === page
                    ? 'bg-brand-500 text-white'
                    : 'border border-surface-300 text-surface-600 hover:bg-surface-50'
                }`}
              >
                {p}
              </button>
            )
          )}

          <button
            onClick={() => onPageChange(page + 1)}
            disabled={page >= totalPagesClamped}
            className="inline-flex items-center justify-center w-8 h-8 rounded-md border border-surface-300 text-sm text-surface-600 hover:bg-surface-50 disabled:opacity-40 disabled:cursor-not-allowed"
            title="Next page"
          >
            ›
          </button>
        </div>
      )}
    </div>
  );
}

// ─── Page ─────────────────────────────────────────────────────────────────

export function EstimatesListPage() {
  const { user } = useAuth();
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const companyId = user?.tenantId as string;

  const [filters, setFilters] = useState<Filters>(DEFAULT_FILTERS);
  const [sort, setSort] = useState<SortState>(DEFAULT_SORT);
  const [page, setPage] = useState(1);
  const perPage = 20;
  const [transitioningIds, setTransitioningIds] = useState<Set<string>>(new Set());
  const [activeActionMenu, setActiveActionMenu] = useState<string | null>(null);

  // Reset to page 1 when filters change
  const handleFilterChange = useCallback((updated: Partial<Filters>) => {
    setFilters((prev) => ({ ...prev, ...updated }));
    setPage(1);
  }, []);

  // Build API params
  const apiParams = useMemo(() => {
    const params: Parameters<typeof estimatesApi.getEstimates>[1] = {
      page,
      per_page: perPage,
      sort_by: sort.field,
      sort_order: sort.order,
      ...(filters.stage ? { stage: filters.stage as EstimateStage } : {}),
      ...(filters.source ? { source: filters.source as EstimateSource } : {}),
      ...(filters.minValue ? { min_value: Number(filters.minValue) } : {}),
      ...(filters.maxValue ? { max_value: Number(filters.maxValue) } : {}),
      ...(filters.search ? { project_type: '' } : {}), // search handled via query key below
    };
    return params;
  }, [page, perPage, sort, filters]);

  // Fetch estimates
  const { data, isLoading, error } = useQuery({
    queryKey: ['estimates-list', companyId, apiParams, filters.search],
    queryFn: () => estimatesApi.getEstimates(companyId, apiParams),
    keepPreviousData: true,
  });

  // Transition mutation
  const transitionMutation = useMutation({
    mutationFn: ({ companyId, estimateId, stage }: { companyId: string; estimateId: string; stage: EstimateStage }) =>
      estimatesApi.transitionEstimate(companyId, estimateId, { stage }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['estimates-list'] });
      queryClient.invalidateQueries({ queryKey: ['estimates-funnel'] });
    },
    onSettled: (_data, _error, variables) => {
      setTransitioningIds((prev) => {
        const next = new Set(prev);
        next.delete(variables.estimateId);
        return next;
      });
    },
  });

  const handleTransition = useCallback(
    (estimateId: string, toStage: EstimateStage) => {
      if (transitioningIds.has(estimateId)) return;
      setTransitioningIds((prev) => new Set(prev).add(estimateId));
      transitionMutation.mutate({ companyId, estimateId, stage: toStage });
    },
    [companyId, transitioningIds, transitionMutation],
  );

  const handleSort = useCallback((field: SortField) => {
    setSort((prev) => ({
      field,
      order: prev.field === field && prev.order === 'asc' ? 'desc' : 'asc',
    }));
  }, []);

  const clearFilters = useCallback(() => {
    setFilters(DEFAULT_FILTERS);
    setPage(1);
  }, []);

  const hasActiveFilters = filters.stage || filters.source || filters.minValue || filters.maxValue || filters.search;

  const SortIcon = ({ field }: { field: SortField }) => {
    if (sort.field !== field) {
      return <ChevronsUpDown className="h-3.5 w-3.5 opacity-40" />;
    }
    return sort.order === 'asc' ? (
      <ChevronUp className="h-3.5 w-3.5" />
    ) : (
      <ChevronDown className="h-3.5 w-3.5" />
    );
  };

  // ─── Loading ─────────────────────────────────────────────────────────
  if (isLoading) {
    return (
      <AppLayout>
        <div className="flex items-center justify-center h-96">
          <LoadingSpinner />
        </div>
      </AppLayout>
    );
  }

  // ─── Error ───────────────────────────────────────────────────────────
  if (error) {
    return (
      <AppLayout>
        <div className="rounded-xl border border-red-200 bg-red-50 p-8 text-center">
          <p className="text-red-700 font-semibold">Failed to load estimates</p>
          <p className="text-red-600 text-sm mt-1">{error.message}</p>
          <button
            onClick={() => queryClient.invalidateQueries({ queryKey: ['estimates-list'] })}
            className="mt-4 inline-flex items-center gap-1.5 rounded-lg bg-red-600 px-4 py-2 text-sm text-white hover:bg-red-700"
          >
            <RotateCcw className="h-4 w-4" />
            Retry
          </button>
        </div>
      </AppLayout>
    );
  }

  const estimates = data?.estimates ?? [];
  const totalPages = Math.max(data?.total_pages ?? data?.pages ?? 1, 1);
  const total = data?.total ?? 0;

  return (
    <AppLayout>
      <div className="space-y-6">
        {/* ─── Header ─────────────────────────────────────────────── */}
        <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
          <div>
            <h1 className="text-2xl font-bold text-surface-900">Estimates</h1>
            <p className="text-sm text-surface-500 mt-1">
              {total} total estimate{total !== 1 ? 's' : ''}
            </p>
          </div>
          <div className="flex items-center gap-2">
            <button
              onClick={() => navigate('/app/estimates')}
              className="inline-flex items-center gap-1.5 rounded-lg border border-surface-300 px-3 py-2 text-sm text-surface-600 hover:bg-surface-50 min-h-[44px]"
            >
              <FileText className="h-4 w-4" />
              Funnel
            </button>
          </div>
        </div>

        {/* ─── Filter Bar ─────────────────────────────────────────── */}
        <div className="rounded-xl border border-surface-200 bg-white p-4">
          <div className="flex items-center gap-2 mb-3">
            <Filter className="h-4 w-4 text-surface-400" />
            <span className="text-xs font-semibold uppercase tracking-wider text-surface-500">Filters</span>
            {hasActiveFilters && (
              <button
                onClick={clearFilters}
                className="ml-auto inline-flex items-center gap-1 text-xs text-brand-600 hover:text-brand-700 font-medium"
              >
                <X className="h-3 w-3" />
                Clear all
              </button>
            )}
          </div>

          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3">
            {/* Search */}
            <div className="relative">
              <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-surface-400" />
              <input
                type="text"
                placeholder="Search customer…"
                value={filters.search}
                onChange={(e) => handleFilterChange({ search: e.target.value })}
                className="w-full rounded-lg border border-surface-300 pl-9 pr-3 py-2 text-sm outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500"
              />
            </div>

            {/* Stage */}
            <select
              value={filters.stage}
              onChange={(e) => handleFilterChange({ stage: e.target.value as EstimateStage | '' })}
              className="rounded-lg border border-surface-300 px-3 py-2 text-sm outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500 bg-white"
            >
              <option value="">All Stages</option>
              {ALL_STAGES.map((s) => (
                <option key={s.value} value={s.value}>{s.label}</option>
              ))}
            </select>

            {/* Source */}
            <select
              value={filters.source}
              onChange={(e) => handleFilterChange({ source: e.target.value as EstimateSource | '' })}
              className="rounded-lg border border-surface-300 px-3 py-2 text-sm outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500 bg-white"
            >
              <option value="">All Sources</option>
              {ALL_SOURCES.map((s) => (
                <option key={s.value} value={s.value}>{s.label}</option>
              ))}
            </select>

            {/* Min value */}
            <input
              type="number"
              placeholder="Min value"
              value={filters.minValue}
              onChange={(e) => handleFilterChange({ minValue: e.target.value })}
              className="rounded-lg border border-surface-300 px-3 py-2 text-sm outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500"
            />

            {/* Max value */}
            <input
              type="number"
              placeholder="Max value"
              value={filters.maxValue}
              onChange={(e) => handleFilterChange({ maxValue: e.target.value })}
              className="rounded-lg border border-surface-300 px-3 py-2 text-sm outline-none focus:border-brand-500 focus:ring-1 focus:ring-brand-500"
            />
          </div>
        </div>

        {/* ─── Data Table ─────────────────────────────────────────── */}
        <div className="rounded-xl border border-surface-200 bg-white overflow-hidden">
          <div className="overflow-x-auto">
            <table className="w-full text-sm">
              <thead>
                <tr className="border-b border-surface-200 bg-surface-50">
                  {SORTABLE_COLUMNS.map((col) => (
                    <th
                      key={col.key}
                      onClick={() => handleSort(col.key)}
                      className="text-left py-3 px-4 text-xs font-semibold uppercase tracking-wider text-surface-500 cursor-pointer hover:text-surface-700 select-none whitespace-nowrap"
                    >
                      <div className="flex items-center gap-1">
                        {col.label}
                        <SortIcon field={col.key} />
                      </div>
                    </th>
                  ))}
                  <th className="text-right py-3 px-4 text-xs font-semibold uppercase tracking-wider text-surface-500">
                    Actions
                  </th>
                </tr>
              </thead>
              <tbody>
                {estimates.length === 0 ? (
                  <tr>
                    <td colSpan={8} className="text-center py-12 text-surface-400">
                      <FileText className="h-10 w-10 mx-auto mb-3 opacity-40" />
                      <p className="font-medium">No estimates found</p>
                      <p className="text-xs mt-1">Try adjusting your filters or create a new estimate</p>
                    </td>
                  </tr>
                ) : (
                  estimates.map((estimate) => {
                    const badge = STAGE_BADGES[estimate.stage];
                    return (
                      <tr
                        key={estimate.id}
                        onClick={() => navigate(`/app/estimates/${estimate.id}`)}
                        className="border-b border-surface-100 last:border-0 hover:bg-surface-50 cursor-pointer transition-colors"
                      >
                        {/* Estimate # */}
                        <td className="py-3 px-4 font-mono text-xs font-semibold text-surface-700 whitespace-nowrap">
                          {estimate.estimate_number}
                        </td>

                        {/* Customer */}
                        <td className="py-3 px-4">
                          <div>
                            <p className="font-medium text-surface-900">{estimate.customer_name}</p>
                            <p className="text-xs text-surface-400">{estimate.customer_email}</p>
                          </div>
                        </td>

                        {/* Project Type */}
                        <td className="py-3 px-4 text-surface-600 whitespace-nowrap">
                          {capitalize(estimate.project_type)}
                        </td>

                        {/* Value */}
                        <td className="py-3 px-4 font-semibold text-surface-900 whitespace-nowrap">
                          {formatCurrency(estimate.total_value)}
                        </td>

                        {/* Stage */}
                        <td className="py-3 px-4 whitespace-nowrap">
                          <div
                            onClick={(e) => e.stopPropagation()}
                          >
                            <StageTransitionBadge
                              estimate={estimate}
                              onTransition={handleTransition}
                              transitioning={transitioningIds.has(estimate.id)}
                            />
                          </div>
                        </td>

                        {/* Source */}
                        <td className="py-3 px-4 text-surface-500 whitespace-nowrap capitalize">
                          {capitalizeSource(estimate.source)}
                        </td>

                        {/* Created */}
                        <td className="py-3 px-4 text-surface-500 whitespace-nowrap">
                          {formatDate(estimate.created_at)}
                        </td>

                        {/* Actions */}
                        <td className="py-3 px-4 text-right whitespace-nowrap">
                          <div
                            className="relative inline-block"
                            onClick={(e) => e.stopPropagation()}
                          >
                            <button
                              onClick={() =>
                                setActiveActionMenu(
                                  activeActionMenu === estimate.id ? null : estimate.id
                                )
                              }
                              className="inline-flex items-center justify-center w-8 h-8 rounded-md hover:bg-surface-200 text-surface-400 hover:text-surface-600 min-h-[32px]"
                              title="Actions"
                            >
                              <MoreVertical className="h-4 w-4" />
                            </button>

                            {activeActionMenu === estimate.id && (
                              <>
                                <div className="fixed inset-0 z-40" onClick={() => setActiveActionMenu(null)} />
                                <div className="absolute right-0 top-full mt-1 z-50 w-44 rounded-lg border border-surface-200 bg-white shadow-lg py-1">
                                  <button
                                    onClick={() => {
                                      navigate(`/app/estimates/${estimate.id}`);
                                      setActiveActionMenu(null);
                                    }}
                                    className="w-full flex items-center gap-2 px-3 py-2 text-sm text-left hover:bg-surface-50"
                                  >
                                    <ArrowRight className="h-3.5 w-3.5 text-surface-400" />
                                    View Details
                                  </button>
                                </div>
                              </>
                            )}
                          </div>
                        </td>
                      </tr>
                    );
                  })
                )}
              </tbody>
            </table>
          </div>

          {/* ─── Pagination ───────────────────────────────────────── */}
          <Pagination
            page={page}
            perPage={perPage}
            total={total}
            totalPages={totalPages}
            onPageChange={setPage}
          />
        </div>
      </div>
    </AppLayout>
  );
}
