"use client";

import { useCallback, useState } from "react";
import { motion } from "framer-motion";
import { CalendarDays, ChevronRight, Clock3, CloudRain, CloudSun, Droplets, RefreshCw, ThermometerSun, Wind, type LucideIcon } from "lucide-react";
import { DayForecastCharts } from "@/components/charts/day-forecast-charts";
import { DayForecastModal } from "@/components/forecast/day-forecast-modal";
import { ForecastIcon } from "@/components/forecast/forecast-icon";
import { ForecastSources } from "@/components/forecast/forecast-sources";
import { LoadingSkeleton } from "@/components/states/loading-skeleton";
import { EmptyState } from "@/components/states/empty-state";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { useForecast } from "@/hooks/use-forecast";
import { useI18n } from "@/lib/i18n";
import {
  formatForecastRainfall,
  formatForecastTemperature,
  formatForecastWind,
  getForecastCondition,
  getHourlyForecastForDay,
  getUpcomingHourlyForecast,
} from "@/lib/forecast-utils";
import type { DailyForecast, HourlyForecast } from "@/types/forecast";

function formatHour(value: string) {
  return value.slice(11, 16);
}

function formatDay(value: string, locale: string, todayLabel: string, index: number) {
  if (index === 0) return todayLabel;
  return new Intl.DateTimeFormat(locale, { weekday: "short", timeZone: "UTC" }).format(new Date(`${value}T12:00:00Z`));
}

function getMaximum(values: Array<number | null>) {
  const availableValues = values.filter((value): value is number => value !== null);
  return availableValues.length ? Math.max(...availableValues) : null;
}

function getMinimum(values: Array<number | null>) {
  const availableValues = values.filter((value): value is number => value !== null);
  return availableValues.length ? Math.min(...availableValues) : null;
}

function getTotal(values: Array<number | null>) {
  const availableValues = values.filter((value): value is number => value !== null);
  return availableValues.length ? availableValues.reduce((total, value) => total + value, 0) : null;
}

function HourlySummaryMetric({ icon: Icon, label, value }: { icon: LucideIcon; label: string; value: string }) {
  return (
    <div className="rounded-card border border-border/60 bg-surface-muted/55 p-3">
      <Icon className="size-4 text-accent" />
      <p className="mt-2 text-[0.62rem] font-semibold uppercase tracking-[0.12em] text-muted">{label}</p>
      <p className="mt-1 text-sm font-semibold">{value}</p>
    </div>
  );
}

function HourlyForecastSummary({ hours }: { hours: HourlyForecast[] }) {
  const { language, t } = useI18n();
  const minimumTemperature = getMinimum(hours.map((hour) => hour.temperature));
  const maximumTemperature = getMaximum(hours.map((hour) => hour.temperature));
  const maximumWind = getMaximum(hours.map((hour) => hour.windSpeed));
  const rainfallTotal = getTotal(hours.map((hour) => hour.precipitation));
  const maximumRainfallProbability = getMaximum(hours.map((hour) => hour.precipitationProbability));
  const temperatureRange = minimumTemperature === null || maximumTemperature === null
    ? "—"
    : `${formatForecastTemperature(minimumTemperature, language)} / ${formatForecastTemperature(maximumTemperature, language)}`;

  return (
    <div className="mt-auto hidden border-t border-border/70 pt-4 lg:block">
      <p className="text-[0.68rem] font-semibold uppercase tracking-[0.14em] text-muted">{t("forecast.nextHoursOverview")}</p>
      <div className="mt-3 grid grid-cols-4 gap-2">
        <HourlySummaryMetric icon={ThermometerSun} label={t("forecast.temperatureRange")} value={temperatureRange} />
        <HourlySummaryMetric icon={Wind} label={t("forecast.maxWind")} value={formatForecastWind(maximumWind, language)} />
        <HourlySummaryMetric icon={CloudRain} label={t("forecast.rainfallTotal")} value={formatForecastRainfall(rainfallTotal, language)} />
        <HourlySummaryMetric icon={Droplets} label={t("forecast.maxProbability")} value={maximumRainfallProbability === null ? "—" : `${maximumRainfallProbability}%`} />
      </div>
    </div>
  );
}

function DailyForecastRow({ day, index, onSelect }: { day: DailyForecast; index: number; onSelect: (day: DailyForecast) => void }) {
  const { language, locale, t } = useI18n();
  const label = formatDay(day.date, locale, t("forecast.today"), index);
  return (
    <motion.li
      initial={{ opacity: 0, y: 8 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ delay: Math.min(index * 0.04, 0.24), duration: 0.28 }}
      className="border-t border-border/65 first:border-t-0"
    >
      <motion.button
        type="button"
        whileTap={{ scale: 0.99 }}
        aria-label={t("forecast.openDayDetails", { day: label })}
        className="grid w-full grid-cols-[4.5rem_minmax(0,1fr)_auto] items-center gap-2 rounded-card px-1 py-3 text-left transition hover:bg-surface-muted/70 focus-visible:outline focus-visible:outline-2 focus-visible:outline-accent sm:grid-cols-[5rem_minmax(0,1fr)_5rem_auto_1rem]"
        onClick={() => onSelect(day)}
      >
        <p className="text-sm font-semibold capitalize">{label}</p>
        <div className="flex min-w-0 items-center gap-2">
          <ForecastIcon code={day.weatherCode} className="size-6 shrink-0 text-accent" />
          <span className="truncate text-xs text-muted">{getForecastCondition(day.weatherCode, language)} · {formatForecastRainfall(day.precipitation, language)}</span>
        </div>
        <span className="hidden items-center gap-1 text-xs text-accent sm:flex"><Droplets className="size-3" />{day.precipitationProbability === null ? "—" : `${day.precipitationProbability}%`}</span>
        <p className="whitespace-nowrap text-sm"><strong>{formatForecastTemperature(day.temperatureMax, language)}</strong><span className="ml-2 text-muted">{formatForecastTemperature(day.temperatureMin, language)}</span></p>
        <ChevronRight className="hidden size-4 text-muted sm:block" />
      </motion.button>
    </motion.li>
  );
}

export function ForecastPanel({ latitude, longitude, locationName }: { latitude?: number; longitude?: number; locationName: string }) {
  const { language, t } = useI18n();
  const { data: forecast, isPending, isError, refetch } = useForecast(latitude, longitude);
  const [selectedDay, setSelectedDay] = useState<DailyForecast | null>(null);
  const closeDayDetails = useCallback(() => setSelectedDay(null), []);
  const upcomingHours = forecast ? getUpcomingHourlyForecast(forecast.hourly) : [];
  const todayHours = forecast?.daily[0] ? getHourlyForecastForDay(forecast.hourly, forecast.daily[0].date) : [];
  const selectedDayHours = forecast && selectedDay ? getHourlyForecastForDay(forecast.hourly, selectedDay.date) : [];

  return (
    <section className="space-y-3">
      <div>
        <p className="section-kicker flex items-center gap-2"><CloudSun className="size-4" />{t("forecast.label")}</p>
        <h2 className="mt-2 text-xl font-semibold tracking-tight">{t("forecast.title")}</h2>
        <p className="mt-1 max-w-3xl text-sm leading-6 text-muted">{t("forecast.description", { location: locationName })}</p>
      </div>

      {!Number.isFinite(latitude) || !Number.isFinite(longitude) || isPending ? (
        <div className="grid gap-3 lg:grid-cols-[1.35fr_1fr]" aria-busy="true">
          <LoadingSkeleton className="h-60" />
          <LoadingSkeleton className="h-60" />
        </div>
      ) : isError || !forecast ? (
        <Card className="flex min-h-40 flex-col items-center justify-center p-6 text-center">
          <p className="text-sm text-muted">{t("forecast.error")}</p>
          <Button variant="glass" className="mt-4" onClick={() => refetch()}><RefreshCw className="size-4" />{t("common.retry")}</Button>
        </Card>
      ) : !forecast.hourly.length || !forecast.daily.length ? (
        <EmptyState title={t("forecast.emptyTitle")} description={t("forecast.emptyDescription")} />
      ) : (
        <div className="space-y-3">
          <div className="grid items-start gap-3 lg:grid-cols-[1.35fr_1fr] lg:items-stretch">
            <Card className="flex flex-col overflow-hidden p-4 sm:p-5 lg:h-full">
              <h3 className="flex items-center gap-2 text-sm font-semibold"><Clock3 className="size-4 text-accent" />{t("forecast.hourly")}</h3>
              <div className="weather-scrollbar -mx-4 mt-4 overflow-x-auto px-4 pb-2 sm:-mx-5 sm:px-5 lg:mt-5">
                <ul className="flex min-w-max gap-2">
                  {upcomingHours.map((hour, index) => (
                    <motion.li
                      key={hour.time}
                      initial={{ opacity: 0, y: 8 }}
                      animate={{ opacity: 1, y: 0 }}
                      transition={{ delay: Math.min(index * 0.018, 0.3), duration: 0.25 }}
                      className="w-[4.6rem] rounded-card border border-border/60 bg-surface-muted/55 px-2 py-3 text-center lg:w-[5.5rem] lg:py-4"
                      title={getForecastCondition(hour.weatherCode, language)}
                    >
                      <p className="text-xs font-medium text-muted">{formatHour(hour.time)}</p>
                      <ForecastIcon code={hour.weatherCode} className="mx-auto my-3 size-6 text-accent" />
                      <p className="text-lg font-semibold tracking-tight">{formatForecastTemperature(hour.temperature, language)}</p>
                      <p className="mt-2 flex items-center justify-center gap-1 text-[0.66rem] text-accent"><Droplets className="size-3" />{hour.precipitationProbability === null ? "—" : `${hour.precipitationProbability}%`}</p>
                      <div className="mt-3 hidden space-y-1.5 border-t border-border/65 pt-3 text-[0.66rem] text-muted lg:block">
                        <p className="flex items-center justify-center gap-1" title={t("forecast.apparentTemperature")}>
                          <ThermometerSun className="size-3 text-accent" />
                          {formatForecastTemperature(hour.feelsLike, language)}
                        </p>
                        <p className="flex items-center justify-center gap-1" title={t("weather.wind")}>
                          <Wind className="size-3 text-accent" />
                          {formatForecastWind(hour.windSpeed, language)}
                        </p>
                        <p className="flex items-center justify-center gap-1" title={t("forecast.precipitation")}>
                          <CloudRain className="size-3 text-accent" />
                          {formatForecastRainfall(hour.precipitation, language)}
                        </p>
                      </div>
                    </motion.li>
                  ))}
                </ul>
              </div>
              <HourlyForecastSummary hours={upcomingHours} />
            </Card>
            <Card className="p-4 sm:p-5">
              <h3 className="flex items-center gap-2 text-sm font-semibold"><CalendarDays className="size-4 text-accent" />{t("forecast.daily")}</h3>
              <ul className="mt-2">{forecast.daily.map((day, index) => <DailyForecastRow day={day} index={index} key={day.date} onSelect={setSelectedDay} />)}</ul>
            </Card>
          </div>
          <DayForecastCharts hours={todayHours} />
        </div>
      )}

      {forecast && <ForecastSources sources={forecast.sources} />}

      <DayForecastModal day={selectedDay} hours={selectedDayHours} locationName={locationName} sources={forecast?.sources ?? []} onClose={closeDayDetails} />
    </section>
  );
}
