import React, { useMemo } from 'react';
import type { ChartOptions, TooltipItem } from 'chart.js';

import ChartCanvas from '../agent-analytics/ChartCanvas';
import EmptyState from '../agent-analytics/EmptyState';
import InfoTooltip from '../agent-analytics/InfoTooltip';
import type { ScanHistoryResponse } from '../../service/visibility/visibility.interface';

import { toneToBadgeClass, trendToMeta } from './helpers';

interface ScanHistoryChartProps {
  scanHistory: ScanHistoryResponse | null;
  loading: boolean;
}

/**
 * Dual-axis line chart showing the weekly Visibility score (left axis)
 * and Share of Voice (right axis) over the backend's retained history.
 * Falls back to grouped bars for a single week.
 */
const ScanHistoryChart = ({
  scanHistory,
  loading,
}: ScanHistoryChartProps): JSX.Element => {
  const history = useMemo(
    () => scanHistory?.history ?? [],
    [scanHistory?.history]
  );

  const sorted = useMemo(
    () =>
      [...history].sort((a, b) => {
        const av = a.week_iso || a.date || '';
        const bv = b.week_iso || b.date || '';

        return av < bv ? -1 : av > bv ? 1 : 0;
      }),
    [history]
  );

  const isSinglePoint = sorted.length <= 1;

  const chartData = useMemo(() => {
    if (isSinglePoint) {
      return {
        labels: sorted.map(point => point.week_iso || point.date || ''),
        datasets: [
          {
            label: 'Visibility score',
            data: sorted.map(point => point.visibility_score ?? 0),
            backgroundColor: 'rgba(183, 0, 124, 0.85)',
            borderColor: '#B7007C',
            borderWidth: 1,
            borderRadius: 8,
            yAxisID: 'y',
            barPercentage: 0.4,
            categoryPercentage: 0.6,
          },
          {
            label: 'Share of voice',
            data: sorted.map(point => point.share_of_voice ?? 0),
            backgroundColor: 'rgba(44, 110, 203, 0.85)',
            borderColor: '#2c6ecb',
            borderWidth: 1,
            borderRadius: 8,
            yAxisID: 'y1',
            barPercentage: 0.4,
            categoryPercentage: 0.6,
          },
        ],
      };
    }

    return {
      labels: sorted.map(point => point.week_iso || point.date || ''),
      datasets: [
        {
          label: 'Visibility score',
          data: sorted.map(point => point.visibility_score ?? 0),
          borderColor: '#B7007C',
          backgroundColor: 'rgba(183, 0, 124, 0.12)',
          pointBackgroundColor: '#B7007C',
          pointBorderColor: '#fff',
          pointBorderWidth: 2,
          borderWidth: 2,
          tension: 0.3,
          pointRadius: 4,
          pointHoverRadius: 6,
          yAxisID: 'y',
          fill: true,
        },
        {
          label: 'Share of voice',
          data: sorted.map(point => point.share_of_voice ?? 0),
          borderColor: '#2c6ecb',
          backgroundColor: 'rgba(44, 110, 203, 0.12)',
          pointBackgroundColor: '#2c6ecb',
          pointBorderColor: '#fff',
          pointBorderWidth: 2,
          borderWidth: 2,
          borderDash: [6, 4],
          tension: 0.3,
          pointRadius: 4,
          pointHoverRadius: 6,
          yAxisID: 'y1',
          fill: false,
        },
      ],
    };
  }, [sorted, isSinglePoint]);

  const tooltipLabel = (
    item: TooltipItem<'line'> | TooltipItem<'bar'>
  ): string => {
    const v = item.parsed.y;
    const unit = item.dataset.yAxisID === 'y1' ? '%' : '/100';

    return `${item.dataset.label ?? ''}: ${v}${unit}`;
  };

  const lineOptions: ChartOptions<'line'> = useMemo(
    () => ({
      responsive: true,
      maintainAspectRatio: false,
      interaction: {
        mode: 'index',
        intersect: false,
      },
      plugins: {
        legend: { position: 'bottom' },
        tooltip: {
          callbacks: { label: tooltipLabel },
        },
      },
      scales: {
        y: {
          type: 'linear',
          position: 'left',
          suggestedMin: 0,
          suggestedMax: 100,
          title: { display: true, text: 'Visibility score' },
        },
        y1: {
          type: 'linear',
          position: 'right',
          suggestedMin: 0,
          suggestedMax: 100,
          grid: { drawOnChartArea: false },
          title: { display: true, text: 'Share of voice (%)' },
        },
      },
    }),
    []
  );

  const barOptions: ChartOptions<'bar'> = useMemo(
    () => ({
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: { position: 'bottom' },
        tooltip: {
          callbacks: { label: tooltipLabel },
        },
      },
      scales: {
        y: {
          type: 'linear',
          position: 'left',
          suggestedMin: 0,
          suggestedMax: 100,
          title: { display: true, text: 'Visibility score' },
        },
        y1: {
          type: 'linear',
          position: 'right',
          suggestedMin: 0,
          suggestedMax: 100,
          grid: { drawOnChartArea: false },
          title: { display: true, text: 'Share of voice (%)' },
        },
      },
    }),
    []
  );

  const trend = trendToMeta(scanHistory?.trend ?? 'stable');
  const trendPct =
    typeof scanHistory?.trend_percentage === 'number'
      ? scanHistory.trend_percentage
      : null;

  return (
    <div className="bg-white rounded-xl border border-gray-200 p-4">
      <div className="flex flex-col gap-3">
        <div className="flex items-center justify-between flex-wrap gap-2">
          <div className="flex items-center gap-2">
            <h2 className="text-base font-semibold text-gray-900">
              Visibility trend
            </h2>
            <InfoTooltip text="Weekly Visibility score (left axis, solid line) and Share of Voice (right axis, dashed line) since the scanner started tracking this brand. Hover the chart for exact values." />
          </div>
          {history.length > 0 && (
            <div className="flex items-center gap-2">
              <span
                className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${toneToBadgeClass(trend.tone)}`}
              >
                {`${trend.arrow} ${trend.label}`}
              </span>
              {trendPct !== null && trendPct !== 0 && (
                <span className="text-xs text-gray-500">
                  {`${trendPct > 0 ? '+' : ''}${trendPct}%`}
                </span>
              )}
            </div>
          )}
        </div>

        {loading && history.length === 0 ? (
          <div
            style={{ height: 280, background: '#f6f7f8', borderRadius: 8 }}
          />
        ) : history.length === 0 ? (
          <EmptyState message="No scan history yet. Run a scan to start building the trend." />
        ) : isSinglePoint ? (
          <ChartCanvas
            type="bar"
            data={chartData}
            options={barOptions}
            height={280}
          />
        ) : (
          <ChartCanvas
            type="line"
            data={chartData}
            options={lineOptions}
            height={280}
          />
        )}
      </div>
    </div>
  );
};

export default ScanHistoryChart;
