import { useMemo, useState } from 'react';
import type { FeatureFilters, FeatureMeta, HexagonStatsResponse, PostcodeFeature } from '../../types';
import type { HexagonLocation } from '../../lib/external-search';
import { formatValue, formatFilterValue, calculateHistogramMean } from '../../lib/format';
import { groupFeaturesByCategory } from '../../lib/features';
import { STACKED_GROUPS, STACKED_ENUM_GROUPS } from '../../lib/consts';
import { DualHistogram, LoadingSkeleton } from './DualHistogram';
import EnumBarChart from './EnumBarChart';
import StackedBarChart from './StackedBarChart';
import StackedEnumChart from './StackedEnumChart';
import PriceHistoryChart from './PriceHistoryChart';
import ExternalSearchLinks from './ExternalSearchLinks';
import { InfoIcon, CloseIcon } from '../ui/icons';
import { CollapsibleGroupHeader } from '../ui/CollapsibleGroupHeader';
import { LightbulbIcon } from '../ui/icons/LightbulbIcon';
import { IconButton } from '../ui/IconButton';
import { FeatureInfoPopup } from '../ui/FeatureInfoPopup';
import { EmptyState } from '../ui/EmptyState';
import { FeatureLabel } from '../ui/FeatureLabel';

interface AreaPaneProps {
  stats: HexagonStatsResponse | null;
  globalFeatures: FeatureMeta[];
  loading: boolean;
  hexagonId: string | null;
  isPostcode?: boolean;
  postcodeData?: PostcodeFeature | null;
  onViewProperties: () => void;
  onClose: () => void;
  hexagonLocation: HexagonLocation | null;
  filters: FeatureFilters;
  onNavigateToSource?: (slug: string, featureName: string) => void;
  aiSummary?: string;
  aiSummaryLoading?: boolean;
  aiSummaryError?: string | null;
  onRetryAiSummary?: () => void;
}

export default function AreaPane({
  stats,
  globalFeatures,
  loading,
  hexagonId,
  isPostcode = false,
  postcodeData,
  onViewProperties,
  onClose,
  hexagonLocation,
  filters,
  onNavigateToSource,
  aiSummary,
  aiSummaryLoading,
  aiSummaryError,
  onRetryAiSummary,
}: AreaPaneProps) {
  // For postcodes, use local data for count
  const propertyCount = isPostcode && postcodeData ? postcodeData.properties.count : stats?.count;
  const featureGroups = useMemo(() => groupFeaturesByCategory(globalFeatures), [globalFeatures]);
  const [infoFeature, setInfoFeature] = useState<FeatureMeta | null>(null);
  const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());

  const toggleGroup = (name: string) =>
    setCollapsedGroups((prev) => {
      const next = new Set(prev);
      if (next.has(name)) next.delete(name);
      else next.add(name);
      return next;
    });

  const numericByName = useMemo(() => {
    if (!stats) return new Map();
    return new Map(stats.numeric_features.map((feature) => [feature.name, feature]));
  }, [stats]);

  const enumByName = useMemo(() => {
    if (!stats) return new Map();
    return new Map(stats.enum_features.map((feature) => [feature.name, feature]));
  }, [stats]);

  const globalFeatureByName = useMemo(
    () => new Map(globalFeatures.map((f) => [f.name, f])),
    [globalFeatures]
  );

  if (!hexagonId) {
    return (
      <EmptyState
        icon={<InfoIcon className="w-8 h-8 text-warm-300 dark:text-warm-600" />}
        title="No area selected"
        description="Click a hexagon or postcode to view area statistics"
        centered
      />
    );
  }

  return (
    <div className="flex flex-col h-full">
      <div className="p-3 border-b border-warm-200 dark:border-navy-700">
        <div className="flex justify-between items-center">
          <div className="flex items-center gap-2">
            <div>
              <h2 className="text-sm font-semibold dark:text-warm-100">
                {isPostcode ? hexagonId : 'Area Statistics'}
              </h2>
              {isPostcode && (
                <span className="text-xs text-warm-500 dark:text-warm-400">Postcode</span>
              )}
            </div>
            {loading && stats && (
              <div className="w-3 h-3 border-2 border-teal-600 dark:border-teal-400 border-t-transparent rounded-full animate-spin" />
            )}
          </div>
          <IconButton onClick={onClose} title="Close">
            <CloseIcon />
          </IconButton>
        </div>
        {propertyCount != null && (
          <p className="text-sm text-warm-600 dark:text-warm-400 mt-1">
            {propertyCount.toLocaleString()} properties
          </p>
        )}
        {!isPostcode && stats && (
          <button
            onClick={onViewProperties}
            className="mt-2 w-full text-sm py-1.5 rounded bg-teal-600 hover:bg-teal-700 text-white font-medium"
          >
            View {stats.count.toLocaleString()} Properties
          </button>
        )}
      </div>

      {hexagonLocation && stats && (
        <ExternalSearchLinks location={hexagonLocation} filters={filters} />
      )}

      {/* AI Summary Card */}
      {(aiSummary || aiSummaryLoading || aiSummaryError) && (
        <div className="px-3 pt-3 pb-1">
          <div className="bg-teal-50 dark:bg-teal-900/20 border border-teal-200 dark:border-teal-800/50 rounded p-2.5">
            <div className="flex items-center gap-1.5 mb-1.5">
              <LightbulbIcon className="w-3.5 h-3.5 text-teal-600 dark:text-teal-400" />
              <span className="text-xs font-semibold text-teal-700 dark:text-teal-400">AI Summary</span>
            </div>
            {aiSummaryError ? (
              <div className="text-xs text-warm-600 dark:text-warm-400">
                <span>Failed to generate summary. </span>
                {onRetryAiSummary && (
                  <button
                    onClick={onRetryAiSummary}
                    className="text-teal-600 dark:text-teal-400 hover:text-teal-800 dark:hover:text-teal-300 underline"
                  >
                    Retry
                  </button>
                )}
              </div>
            ) : aiSummaryLoading ? (
              <div className="space-y-1.5">
                <div className="h-3 bg-teal-200/60 dark:bg-teal-800/40 rounded animate-pulse w-full" />
                <div className="h-3 bg-teal-200/60 dark:bg-teal-800/40 rounded animate-pulse w-4/5" />
              </div>
            ) : (
              <p className="text-xs text-warm-700 dark:text-warm-300 leading-relaxed">
                {aiSummary}
              </p>
            )}
          </div>
        </div>
      )}

      <div className="flex-1 overflow-y-auto">
        {loading && !stats ? (
          <LoadingSkeleton />
        ) : stats ? (
          <div>
            {/* Histogram color legend */}
            <div className="mx-3 mt-3 bg-teal-50 dark:bg-teal-900/20 border border-teal-200 dark:border-teal-800/50 rounded p-2.5 text-xs">
              <div className="space-y-1.5">
                <div className="flex items-center gap-2">
                  <div className="w-3 h-3 bg-teal-500 dark:bg-teal-400 rounded" />
                  <span className="text-warm-700 dark:text-warm-300">
                    <span className="font-medium text-warm-900 dark:text-warm-100">Teal bars</span> show the distribution in this selected area
                  </span>
                </div>
                <div className="flex items-center gap-2">
                  <div className="w-3 h-3 bg-warm-300/60 dark:bg-warm-600/60 rounded" />
                  <span className="text-warm-700 dark:text-warm-300">
                    <span className="font-medium text-warm-900 dark:text-warm-100">Gray bars</span> show the overall distribution across all areas
                  </span>
                </div>
                <div className="flex items-center gap-2">
                  <div className="w-3 h-px border-t border-dashed border-warm-500 dark:border-warm-400" />
                  <span className="text-warm-700 dark:text-warm-300">
                    <span className="font-medium text-warm-900 dark:text-warm-100">Dashed line</span> indicates the global average
                  </span>
                </div>
              </div>
            </div>
            {featureGroups.map((group) => {
              const hasData = group.features.some(
                (feature) => numericByName.has(feature.name) || enumByName.has(feature.name)
              );
              if (!hasData) return null;

              const stackedCharts = STACKED_GROUPS[group.name];
              const stackedEnumCharts = STACKED_ENUM_GROUPS[group.name];

              // Features that are part of a stacked enum config (rendered as compact charts)
              const stackedEnumFeatureNames = new Set(
                stackedEnumCharts?.flatMap((c) =>
                  [c.feature, ...c.components].filter(Boolean)
                ) as string[] ?? []
              );

              const isExpanded = !collapsedGroups.has(group.name);

              return (
                <div key={group.name}>
                  <CollapsibleGroupHeader
                    name={group.name}
                    expanded={isExpanded}
                    onToggle={() => toggleGroup(group.name)}
                    className="px-3 py-1.5 text-xs font-bold text-warm-500 bg-warm-50 dark:bg-warm-900 dark:text-warm-400 sticky top-0 hover:bg-warm-100 dark:hover:bg-warm-800"
                  />
                  {isExpanded && <div className="px-3 py-2 space-y-3">
                    {/* Price History in Property group */}
                    {group.name === 'Property' && stats.price_history && (() => {
                      // Only show chart if there are at least 2 unique years
                      const uniqueYears = new Set(stats.price_history.map(p => Math.floor(p.year)));
                      return uniqueYears.size > 1;
                    })() && (
                      <div className="bg-warm-50 dark:bg-warm-800 rounded p-2">
                        <span className="text-xs text-warm-700 dark:text-warm-300">Price History</span>
                        <PriceHistoryChart points={stats.price_history} />
                      </div>
                    )}
                    {stackedCharts
                      ? // Render stacked charts for this group
                        stackedCharts.map((chart) => {
                          const segments = chart.components
                            .map((name) => ({
                              name,
                              value: numericByName.get(name)?.mean ?? 0,
                            }))
                            .filter((s) => s.value > 0);

                          // Use aggregate feature stats if available, otherwise sum components
                          const aggregateStats = chart.feature
                            ? numericByName.get(chart.feature)
                            : undefined;
                          const total = aggregateStats
                            ? aggregateStats.mean
                            : segments.reduce((sum, s) => sum + s.value, 0);

                          const featureMeta = chart.feature
                            ? globalFeatureByName.get(chart.feature)
                            : undefined;

                          if (total === 0) return null;

                          return (
                            <div
                              key={chart.label}
                              className="bg-warm-50 dark:bg-warm-800 rounded p-2"
                            >
                              <div className="flex justify-between items-baseline mb-1.5">
                                {featureMeta ? (
                                  <FeatureLabel
                                    feature={{ ...featureMeta, name: chart.label }}
                                    onShowInfo={setInfoFeature}
                                    className="mr-2"
                                  />
                                ) : (
                                  <span className="text-xs text-warm-700 dark:text-warm-300 truncate mr-2">
                                    {chart.label}
                                  </span>
                                )}
                                <span className="text-xs font-semibold text-teal-700 dark:text-teal-400 whitespace-nowrap">
                                  {formatValue(total)}
                                  {chart.unit ? ` ${chart.unit}` : ''}
                                </span>
                              </div>
                              <StackedBarChart segments={segments} total={total} />
                            </div>
                          );
                        })
                      : // Default: render each feature individually (skip stacked enum features)
                        group.features
                          .filter((f) => !stackedEnumFeatureNames.has(f.name))
                          .map((feature) => {
                            const numericStats = numericByName.get(feature.name);
                            const enumStats = enumByName.get(feature.name);

                            if (numericStats) {
                              const globalFeature = globalFeatureByName.get(feature.name);
                              const globalHistogram = globalFeature?.histogram;
                              const globalMean = globalHistogram
                                ? calculateHistogramMean(globalHistogram)
                                : undefined;

                              return (
                                <div
                                  key={feature.name}
                                  className="bg-warm-50 dark:bg-warm-800 rounded p-2"
                                >
                                  <div className="flex justify-between items-baseline">
                                    <FeatureLabel
                                      feature={feature}
                                      onShowInfo={setInfoFeature}
                                      className="mr-2"
                                    />
                                    <span className="text-xs font-semibold text-teal-700 dark:text-teal-400 whitespace-nowrap">
                                      {formatValue(numericStats.mean, feature)}
                                    </span>
                                  </div>
                                  {numericStats.histogram && (
                                    globalHistogram ? (
                                      <DualHistogram
                                        localCounts={numericStats.histogram.counts}
                                        globalCounts={globalHistogram.counts}
                                        p1={numericStats.histogram.p1}
                                        p99={numericStats.histogram.p99}
                                        globalMean={globalMean}
                                        formatLabel={formatFilterValue}
                                      />
                                    ) : (
                                      <DualHistogram
                                        localCounts={numericStats.histogram.counts}
                                        globalCounts={numericStats.histogram.counts}
                                        p1={numericStats.histogram.p1}
                                        p99={numericStats.histogram.p99}
                                        formatLabel={formatFilterValue}
                                      />
                                    )
                                  )}
                                </div>
                              );
                            }

                            if (enumStats) {
                              return (
                                <div
                                  key={feature.name}
                                  className="bg-warm-50 dark:bg-warm-800 rounded p-2"
                                >
                                  <FeatureLabel feature={feature} onShowInfo={setInfoFeature} />
                                  <EnumBarChart counts={enumStats.counts} />
                                </div>
                              );
                            }

                            return null;
                          })}
                    {/* Stacked enum charts */}
                    {stackedEnumCharts?.map((chart) => {
                      const featureMeta = chart.feature
                        ? globalFeatureByName.get(chart.feature)
                        : undefined;

                      // Single component: render as a stacked bar (like crime charts)
                      if (chart.components.length === 1) {
                        const stats = enumByName.get(chart.components[0]);
                        if (!stats) return null;

                        const segments = chart.valueOrder
                          .map((value) => ({ name: value, value: stats.counts[value] ?? 0 }))
                          .filter((s) => s.value > 0);
                        const total = segments.reduce((sum, s) => sum + s.value, 0);
                        if (total === 0) return null;

                        return (
                          <div
                            key={chart.label}
                            className="bg-warm-50 dark:bg-warm-800 rounded p-2"
                          >
                            <div className="flex justify-between items-baseline mb-1.5">
                              {featureMeta ? (
                                <FeatureLabel
                                  feature={featureMeta}
                                  onShowInfo={setInfoFeature}
                                  className="mr-2"
                                />
                              ) : (
                                <span className="text-xs text-warm-700 dark:text-warm-300 truncate mr-2">
                                  {chart.label}
                                </span>
                              )}
                              <span className="text-xs font-semibold text-teal-700 dark:text-teal-400 whitespace-nowrap">
                                {total.toLocaleString()}
                              </span>
                            </div>
                            <StackedBarChart
                              segments={segments}
                              total={total}
                              colorMap={Object.fromEntries(
                                chart.valueOrder.map((v, i) => [v, chart.valueColors[i]])
                              )}
                            />
                          </div>
                        );
                      }

                      // Multi-component: render as compact multi-row chart (like risk features)
                      const components = chart.components
                        .map((name) => {
                          const stats = enumByName.get(name);
                          return stats ? { label: name, stats } : null;
                        })
                        .filter((c): c is NonNullable<typeof c> => c !== null);

                      if (components.length === 0) return null;

                      return (
                        <div
                          key={chart.label}
                          className="bg-warm-50 dark:bg-warm-800 rounded p-2"
                        >
                          <div className="mb-1.5">
                            {featureMeta ? (
                              <FeatureLabel
                                feature={{ ...featureMeta, name: chart.label }}
                                onShowInfo={setInfoFeature}
                              />
                            ) : (
                              <span className="text-xs text-warm-700 dark:text-warm-300">
                                {chart.label}
                              </span>
                            )}
                          </div>
                          <StackedEnumChart
                            components={components}
                            valueOrder={chart.valueOrder}
                            valueColors={chart.valueColors}
                          />
                        </div>
                      );
                    })}
                  </div>}
                </div>
              );
            })}
            {/* Google Street View */}
            {hexagonLocation && (
              <div>
                <div className="px-3 py-1.5 text-xs font-bold text-warm-500 bg-warm-50 dark:bg-warm-900 dark:text-warm-400 sticky top-0">
                  Street View
                </div>
                <div className="px-3 py-2">
                  <div className="rounded overflow-hidden border border-warm-200 dark:border-warm-700">
                    <iframe
                      className="w-full"
                      style={{ height: 240, border: 0 }}
                      loading="lazy"
                      referrerPolicy="no-referrer-when-downgrade"
                      src={`https://maps.google.com/maps?layer=c&cbll=${hexagonLocation.lat},${hexagonLocation.lon}&cbp=11,0,0,0,0&output=svembed`}
                    />
                  </div>
                </div>
              </div>
            )}
          </div>
        ) : null}
      </div>

      {infoFeature && (
        <FeatureInfoPopup
          feature={infoFeature}
          onClose={() => setInfoFeature(null)}
          onNavigateToSource={onNavigateToSource}
        />
      )}
    </div>
  );
}
