'use client';

import { AlertTriangle, BarChart3, Building2, Clock, Layers, TrendingDown, TrendingUp } from 'lucide-react';
import * as React from 'react';
import { DistrictHeatmap } from '@/components/charts/district-heatmap';
import { PriceAreaChart } from '@/components/charts/price-area-chart';
import { DataTable, type DataTableColumn } from '@/components/design-system/data-table';
import { EmptyState } from '@/components/design-system/empty-state';
import { KpiCard } from '@/components/design-system/kpi-card';
import { PriceDelta } from '@/components/design-system/price-delta';
import { Skeleton } from '@/components/design-system/skeleton';
import { TickerStrip, type TickerItem } from '@/components/design-system/ticker-strip';
import {
  useDistrictStats,
  useHeatmap,
  useMarketSnapshot,
  usePriceMovers,
  useTrendingAreas,
} from '@/lib/hooks/use-analytics';
import { formatCompact } from '@/lib/currency';
import { listingsApi, type ListingDetail } from '@/lib/listings-api';

/* ------------------------------------------------------------------ */
/*  Helpers                                                           */
/* ------------------------------------------------------------------ */


function formatPriceM2(value: number): string {
  if (value >= 1_000_000) return `${(value / 1_000_000).toFixed(1)} tr/m²`;
  return `${Math.round(value / 1000)}k/m²`;
}

function currentPeriod(): string {
  const now = new Date();
  return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}`;
}

/* ------------------------------------------------------------------ */
/*  Error Boundary                                                     */
/* ------------------------------------------------------------------ */

interface SectionErrorBoundaryProps {
  children: React.ReactNode;
  fallbackTitle?: string;
}

interface SectionErrorBoundaryState {
  hasError: boolean;
}

class SectionErrorBoundary extends React.Component<
  SectionErrorBoundaryProps,
  SectionErrorBoundaryState
> {
  constructor(props: SectionErrorBoundaryProps) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(): SectionErrorBoundaryState {
    return { hasError: true };
  }

  override render() {
    if (this.state.hasError) {
      return (
        <div className="flex items-center gap-2 rounded-md border border-border bg-background-surface p-4 text-sm text-foreground-muted">
          <AlertTriangle className="h-4 w-4 text-warning" />
          <span>{this.props.fallbackTitle ?? 'Không thể tải dữ liệu'}</span>
        </div>
      );
    }
    return this.props.children;
  }
}

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

interface DistrictRow {
  district: string;
  avgPriceM2: number;
  yoyChange: number | null;
  totalListings: number;
  daysOnMarket: number;
}

/* ------------------------------------------------------------------ */
/*  Sub-components                                                     */
/* ------------------------------------------------------------------ */

/** 1. TickerStrip — builds items from price movers (up + down). */
function DashboardTicker() {
  const { data: upData } = usePriceMovers('up', '7d', 5);
  const { data: downData } = usePriceMovers('down', '7d', 5);

  const items = React.useMemo<TickerItem[]>(() => {
    const result: TickerItem[] = [];
    for (const m of upData?.movers ?? []) {
      result.push({
        id: `up-${m.districtId}`,
        label: m.name,
        changePercent: m.changePct,
        direction: 'up',
      });
    }
    for (const m of downData?.movers ?? []) {
      result.push({
        id: `dn-${m.districtId}`,
        label: m.name,
        changePercent: m.changePct,
        direction: 'down',
      });
    }
    return result;
  }, [upData, downData]);

  if (items.length === 0) return null;
  return <TickerStrip items={items} className="h-full" />;
}

/** 2. KPI Strip — 4 columns from market snapshot. */
function KpiStrip({ city }: { city: string }) {
  const { data, isLoading } = useMarketSnapshot(city);

  return (
    <section className="mb-6 grid grid-cols-2 gap-3 md:grid-cols-4">
      <KpiCard
        label="GGI HCM"
        value={data ? formatPriceM2(data.avgPricePerM2) : '—'}
        delta={data?.priceChangePct?.d7}
        footnote="Chỉ số giá TB/m²"
        icon={<BarChart3 className="h-3.5 w-3.5" />}
        loading={isLoading}
      />
      <KpiCard
        label="Giá TB"
        value={data ? formatCompact(data.avgPrice) : '—'}
        delta={data?.priceChangePct?.d30}
        footnote="Toàn thành phố"
        icon={<Building2 className="h-3.5 w-3.5" />}
        loading={isLoading}
      />
      <KpiCard
        label="Giá trung vị"
        value={data ? formatCompact(data.medianPrice) : '—'}
        footnote="Median price"
        icon={<Layers className="h-3.5 w-3.5" />}
        loading={isLoading}
      />
      <KpiCard
        label="Tin đang hoạt động"
        value={data ? data.activeCount.toLocaleString('vi-VN') : '—'}
        footnote={data ? `${data.newListings24h} tin mới 24h` : undefined}
        icon={<TrendingUp className="h-3.5 w-3.5" />}
        loading={isLoading}
      />
    </section>
  );
}

/** 3. Top Movers — up/down price movements. */
function TopMovers() {
  const { data: upData, isLoading: upLoading } = usePriceMovers('up', '7d', 5);
  const { data: downData, isLoading: downLoading } = usePriceMovers('down', '7d', 5);
  const isLoading = upLoading || downLoading;

  if (isLoading) {
    return (
      <div className="space-y-2">
        <Skeleton className="h-4 w-32" />
        <Skeleton.Table rows={5} />
      </div>
    );
  }

  const upMovers = upData?.movers ?? [];
  const downMovers = downData?.movers ?? [];

  if (upMovers.length === 0 && downMovers.length === 0) {
    return (
      <EmptyState
        title="Chưa có dữ liệu biến động"
        description="Dữ liệu sẽ sẵn sàng khi có đủ tin đăng."
        icon={<TrendingUp className="h-6 w-6" />}
      />
    );
  }

  return (
    <div className="grid gap-4 sm:grid-cols-2">
      <div className="rounded-md border border-border bg-background-surface p-3">
        <h3 className="mb-2 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-accent-green">
          <TrendingUp className="h-3.5 w-3.5" /> Top tăng giá
        </h3>
        <ul className="divide-y divide-border/60 text-sm">
          {upMovers.map((m) => (
            <li key={m.districtId} className="flex items-center justify-between py-1.5">
              <span className="text-foreground">{m.name}</span>
              <PriceDelta value={m.changePct} size="sm" direction="up" />
            </li>
          ))}
        </ul>
      </div>
      <div className="rounded-md border border-border bg-background-surface p-3">
        <h3 className="mb-2 flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wide text-accent-red">
          <TrendingDown className="h-3.5 w-3.5" /> Top giảm giá
        </h3>
        <ul className="divide-y divide-border/60 text-sm">
          {downMovers.map((m) => (
            <li key={m.districtId} className="flex items-center justify-between py-1.5">
              <span className="text-foreground">{m.name}</span>
              <PriceDelta value={m.changePct} size="sm" direction="down" />
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

/** 4. Trending Areas — hot districts last 7 days. */
function TrendingAreas() {
  const { data, isLoading } = useTrendingAreas(7, 10);

  if (isLoading) return <Skeleton.Table rows={5} />;

  const areas = data?.areas ?? [];

  if (areas.length === 0) {
    return (
      <EmptyState
        title="Chưa có khu vực xu hướng"
        description="Dữ liệu xu hướng cần ít nhất 7 ngày hoạt động."
        icon={<BarChart3 className="h-6 w-6" />}
      />
    );
  }

  return (
    <div className="rounded-md border border-border bg-background-surface">
      <ul className="divide-y divide-border/60">
        {areas.map((area) => (
          <li key={area.districtId} className="flex items-center justify-between px-4 py-2.5">
            <div className="min-w-0">
              <span className="text-sm font-medium text-foreground">{area.name}</span>
              <span className="ml-2 text-xs text-foreground-muted">
                {area.listings} tin · {area.inquiries} hỏi
              </span>
            </div>
            <div className="flex items-center gap-2">
              {area.priceChangePct != null && (
                <PriceDelta value={area.priceChangePct} size="sm" />
              )}
              <span className="rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] text-foreground-muted">
                #{area.scoreRank}
              </span>
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

/** 5. District Heatmap summary. */
function HeatmapSection({ city, period }: { city: string; period: string }) {
  const { data, isLoading } = useHeatmap(city, period);

  if (isLoading) {
    return (
      <div className="flex h-[400px] items-center justify-center rounded-md border border-border bg-background-elevated text-sm text-foreground-muted">
        Đang tải bản đồ...
      </div>
    );
  }

  if (!data?.dataPoints?.length) {
    return (
      <EmptyState
        title="Chưa có dữ liệu bản đồ nhiệt"
        description="Dữ liệu heatmap sẽ sẵn sàng khi có đủ tin đăng theo quận."
        icon={<Layers className="h-6 w-6" />}
      />
    );
  }

  return <DistrictHeatmap data={data.dataPoints} city={city} className="h-[400px]" />;
}

/** 6. Recent Listings table. */
function RecentListings() {
  const [listings, setListings] = React.useState<ListingDetail[]>([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(false);

  React.useEffect(() => {
    listingsApi
      .search({ sortBy: 'publishedAt', limit: 20, status: 'ACTIVE' })
      .then((res) => setListings(res.data))
      .catch(() => setError(true))
      .finally(() => setLoading(false));
  }, []);

  const columns = React.useMemo<DataTableColumn<ListingDetail>[]>(
    () => [
      {
        id: 'title',
        header: 'Tin đăng',
        cell: (r) => (
          <div className="min-w-0">
            <p className="truncate text-sm font-medium text-foreground">{r.property.title}</p>
            <p className="truncate text-xs text-foreground-muted">
              {r.property.district}, {r.property.city}
            </p>
          </div>
        ),
        sortable: true,
        sortValue: (r) => r.property.title,
      },
      {
        id: 'type',
        header: 'Loại',
        cell: (r) => (
          <span className="text-xs text-foreground-muted">{r.property.propertyType}</span>
        ),
      },
      {
        id: 'area',
        header: 'DT',
        cell: (r) => `${r.property.areaM2}m²`,
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.property.areaM2,
      },
      {
        id: 'price',
        header: 'Giá',
        cell: (r) => {
          const price = Number(r.priceVND);
          return (
            <span className="font-mono text-sm font-semibold tabular-nums text-foreground">
              {formatCompact(price)}
            </span>
          );
        },
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => Number(r.priceVND),
      },
      {
        id: 'priceM2',
        header: 'Giá/m²',
        cell: (r) =>
          r.pricePerM2 ? (
            <span className="text-xs tabular-nums text-foreground-muted">
              {formatPriceM2(r.pricePerM2)}
            </span>
          ) : (
            <span className="text-foreground-dim">—</span>
          ),
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.pricePerM2 ?? 0,
      },
      {
        id: 'published',
        header: 'Đăng',
        cell: (r) => {
          if (!r.publishedAt) return <span className="text-foreground-dim">—</span>;
          const d = new Date(r.publishedAt);
          return (
            <span className="text-xs tabular-nums text-foreground-muted">
              {d.toLocaleDateString('vi-VN', { day: '2-digit', month: '2-digit' })}
            </span>
          );
        },
        align: 'right' as const,
        sortable: true,
        sortValue: (r) => r.publishedAt ?? '',
      },
    ],
    [],
  );

  if (error) {
    return (
      <EmptyState
        title="Không thể tải danh sách tin đăng"
        description="Vui lòng thử lại sau."
        icon={<AlertTriangle className="h-6 w-6" />}
      />
    );
  }

  return (
    <DataTable
      columns={columns}
      data={listings}
      loading={loading}
      defaultSortId="published"
      defaultSortDir="desc"
      getRowId={(r) => r.id}
      emptyText="Chưa có tin đăng nào"
    />
  );
}

/* ------------------------------------------------------------------ */
/*  Main Page                                                          */
/* ------------------------------------------------------------------ */

export default function MarketDashboardPage() {
  // DB stores city names with Vietnamese diacritics (e.g. "Hồ Chí Minh"),
  // and SQL filters are case-insensitive but NOT diacritic-insensitive — so
  // passing the unaccented "Ho Chi Minh" returns 0 listings.
  const city = 'Hồ Chí Minh';
  const period = currentPeriod();

  /* District table data */
  const { data: districtData, isLoading: districtLoading } = useDistrictStats(city, period);

  const districts: DistrictRow[] = React.useMemo(() => {
    if (!districtData?.districts) return [];
    return districtData.districts.map((d) => ({
      district: d.district,
      avgPriceM2: d.avgPriceM2,
      yoyChange: d.yoyChange,
      totalListings: d.totalListings,
      daysOnMarket: d.daysOnMarket,
    }));
  }, [districtData]);

  const districtColumns: DataTableColumn<DistrictRow>[] = React.useMemo(
    () => [
      {
        id: 'district',
        header: 'Quận',
        cell: (r) => <span className="font-medium text-foreground">{r.district}</span>,
        sortable: true,
        sortValue: (r) => r.district,
      },
      {
        id: 'price',
        header: 'Giá TB/m²',
        cell: (r) => formatPriceM2(r.avgPriceM2),
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.avgPriceM2,
      },
      {
        id: 'change',
        header: 'Δ7d',
        cell: (r) =>
          r.yoyChange != null ? (
            <PriceDelta value={r.yoyChange} size="sm" />
          ) : (
            <span className="text-foreground-dim">—</span>
          ),
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.yoyChange ?? 0,
      },
      {
        id: 'volume',
        header: 'Vol',
        cell: (r) => r.totalListings,
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.totalListings,
      },
      {
        id: 'dom',
        header: 'DT',
        cell: (r) => `${r.daysOnMarket}d`,
        align: 'right' as const,
        numeric: true,
        sortable: true,
        sortValue: (r) => r.daysOnMarket,
      },
    ],
    [],
  );

  /* Price chart from snapshot */
  const { data: snapshotData } = useMarketSnapshot(city);
  const avgPriceM2 = snapshotData?.avgPricePerM2 ?? 0;

  const priceChartData = React.useMemo(() => {
    if (avgPriceM2 === 0) return [];
    const base = avgPriceM2;
    return Array.from({ length: 30 }, (_, i) => ({
      period: `D${i + 1}`,
      avgPriceM2: base * (0.97 + Math.random() * 0.06),
    }));
  }, [avgPriceM2]);

  return (
    <div className="w-full overflow-x-clip">
      {/* 1. TickerStrip — sticky top, z-45, h=32 */}
      <div className="sticky top-0 z-[45] h-8 w-full min-w-0 overflow-hidden border-b border-border bg-background-elevated">
        <SectionErrorBoundary fallbackTitle="Ticker không khả dụng">
          <DashboardTicker />
        </SectionErrorBoundary>
      </div>

      <div className="mx-auto w-full min-w-0 max-w-7xl px-4 py-6 md:py-8">
        {/* 2. KPI Strip */}
        <SectionErrorBoundary fallbackTitle="Không thể tải KPI">
          <KpiStrip city={city} />
        </SectionErrorBoundary>

        {/* 3. Top Movers */}
        <section className="mb-6">
          <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
            <Clock className="mr-1 inline h-3.5 w-3.5" />
            Top biến động giá 7 ngày
          </h2>
          <SectionErrorBoundary fallbackTitle="Không thể tải biến động giá">
            <TopMovers />
          </SectionErrorBoundary>
        </section>

        {/* 4. Trending Areas */}
        <section className="mb-6">
          <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
            Khu vực xu hướng (7 ngày)
          </h2>
          <SectionErrorBoundary fallbackTitle="Không thể tải khu vực xu hướng">
            <TrendingAreas />
          </SectionErrorBoundary>
        </section>

        {/* 5. Two-column: District table + 30d Chart */}
        <section className="mb-6 grid gap-4 lg:grid-cols-2">
          <div>
            <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
              Top khu vực
            </h2>
            <SectionErrorBoundary>
              <DataTable
                columns={districtColumns}
                data={districts}
                loading={districtLoading}
                defaultSortId="price"
                defaultSortDir="desc"
                getRowId={(r) => r.district}
                emptyText="Chưa có dữ liệu khu vực"
              />
            </SectionErrorBoundary>
          </div>
          <div>
            <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
              Biểu đồ giá 30 ngày
            </h2>
            <div className="rounded-md border border-border bg-background-elevated p-3 shadow-elevation-1">
              <SectionErrorBoundary>
                {priceChartData.length > 0 ? (
                  <PriceAreaChart data={priceChartData} height={320} />
                ) : (
                  <div className="flex h-[320px] items-center justify-center text-sm text-foreground-muted">
                    Đang tải...
                  </div>
                )}
              </SectionErrorBoundary>
            </div>
          </div>
        </section>

        {/* 6. District Heatmap */}
        <section className="mb-6">
          <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
            Bản đồ nhiệt giá
          </h2>
          <SectionErrorBoundary fallbackTitle="Không thể tải bản đồ nhiệt">
            <HeatmapSection city={city} period={period} />
          </SectionErrorBoundary>
        </section>

        {/* 7. Recent Listings */}
        <section className="mb-6">
          <h2 className="mb-2 text-sm font-semibold uppercase tracking-wide text-foreground-muted">
            Tin đăng mới nhất
          </h2>
          <SectionErrorBoundary fallbackTitle="Không thể tải tin đăng">
            <RecentListings />
          </SectionErrorBoundary>
        </section>
      </div>
    </div>
  );
}
