"use client";

import { useState, useCallback, useEffect, useMemo } from "react";
import dynamic from "next/dynamic";
import { useTranslations } from "next-intl";
import { useSensorHub } from "@/hooks/useSensorHub";
import Box from "@mui/material/Box";
import CircularProgress from "@mui/material/CircularProgress";
import LinearProgress from "@mui/material/LinearProgress";
import CropZoningMap from "./CropZoningMap";
import ZoneLegend from "./ZoneLegend";
import LayerControl from "./LayerControl";
import ZoneDetailPanel from "./ZoneDetailPanel";
import CropZoningWeatherSection from "./CropZoningWeatherSection";
import {
  cropZoningService,
  type Product,
  type ZoneInitialData,
  type ZoneDetailData,
} from "@/libs/api/services/cropZoningService";
import { CROP_COLORS, type CropType } from "./cropZoningTypes";
import type { LayerType } from "./cropZoningTypes";
import type { MapDrawGeoJSON } from "./CropZoningMap";

const MapComponent = dynamic(() => Promise.resolve(CropZoningMap), {
  ssr: false,
  loading: () => (
    <Box className="flex items-center justify-center bs-full min-bs-[400px] rounded-xl bg-action-hover">
      <CircularProgress size={48} />
    </Box>
  ),
});

const POLL_INTERVAL = 2000;
const MAX_POLLS = 100;
const ZONES_PAGE_SIZE = 100;
const getNormalizedTaskStatus = (status?: string) => status?.toLowerCase();

const mergeZones = (pages: ZoneInitialData[][]) =>
  pages
    .flat()
    .sort((left, right) => (left.sequence ?? 0) - (right.sequence ?? 0));

export default function CropZoningWrapper() {
  const t = useTranslations("cropZoning");
  const { sensorHub } = useSensorHub();
  const [areaGeoJson, setAreaGeoJson] = useState<MapDrawGeoJSON>(null);
  const [isClientReady, setIsClientReady] = useState(false);
  const [loading, setLoading] = useState(true);
  const [progress, setProgress] = useState<{ message: string; percent: number } | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [zonesData, setZonesData] = useState<ZoneInitialData[] | null>(null);
  const [products, setProducts] = useState<Product[]>([]);
  const [activeLayer, setActiveLayer] = useState<LayerType>("crops");
  const [selectedZone, setSelectedZone] = useState<ZoneDetailData | null>(null);
  const [panelOpen, setPanelOpen] = useState(false);

  useEffect(() => {
    setIsClientReady(true);
  }, []);

  useEffect(() => {
    cropZoningService.getProducts()
      .then(res => setProducts(res.products))
      .catch(() => setProducts([]));
  }, []);

  useEffect(() => {
    let cancelled = false;

    const loadArea = async () => {
      if (!isClientReady) return;

      if (!sensorHub?.id) {
        setError(t("errors.noSensor"));
        setLoading(false);
        return;
      }

      setLoading(true);
      setError(null);
      setProgress({ message: t("loadingArea"), percent: 0 });

      try {
        let polls = 0;

        const loadAllZonePages = async (
          firstResponse: Extract<
            Awaited<ReturnType<typeof cropZoningService.getArea>>,
            { area: unknown }
          >,
          completedTaskMessage?: string,
        ) => {
          setAreaGeoJson(firstResponse.area as unknown as MapDrawGeoJSON);

          const firstPageZones = firstResponse.zones ?? [];
          const totalPages = Math.max(firstResponse.pagination?.total_pages ?? 1, 1);
          const pageSize = firstResponse.pagination?.page_size ?? ZONES_PAGE_SIZE;
          const zonePages: ZoneInitialData[][] = [firstPageZones];

          setZonesData(firstPageZones as ZoneInitialData[]);
          setProgress({
            message: totalPages > 1 ? `${t("loadingArea")} (1/${totalPages})` : completedTaskMessage || t("loadingArea"),
            percent: totalPages > 1 ? 80 : 100,
          });

          for (let page = 2; page <= totalPages; page++) {
            if (cancelled) break;

            const pageRes = await cropZoningService.getArea(sensorHub.id, {
              page,
              pageSize,
            });

            if (!("area" in pageRes)) {
              throw new Error(t("errors.areaLoadFailed"));
            }

            zonePages.push(pageRes.zones ?? []);

            const mergedZones = mergeZones(zonePages);
            const pagesLoaded = zonePages.length;
            const pagesProgress =
              totalPages > 0 ? Math.round((pagesLoaded / totalPages) * 20) : 20;

            setZonesData(mergedZones);
            setProgress({
              message: `${t("loadingArea")} (${pagesLoaded}/${totalPages})`,
              percent: Math.min(80 + pagesProgress, 100),
            });
          }

          if (!cancelled) {
            setZonesData(mergeZones(zonePages));
            setProgress({
              message: completedTaskMessage || t("loadingArea"),
              percent: 100,
            });
          }
        };

        while (!cancelled && polls < MAX_POLLS) {
          const res = await cropZoningService.getArea(sensorHub.id, {
            page: 1,
            pageSize: ZONES_PAGE_SIZE,
          });

          if (!("area" in res)) break;

          const task = res.task;
          const taskStatus = getNormalizedTaskStatus(task?.status);

          if (task) {
            setProgress({
              message: task.message || task.stage_label || t("loadingArea"),
              percent: Math.min(Math.round((task.progress_percent || 0) * 0.8), 80),
            });
          }

          if (taskStatus === "completed" || taskStatus === "success") {
            await loadAllZonePages(
              res,
              task?.message || task?.stage_label || t("loadingArea"),
            );
            break;
          }

          if ((!task && res.area) || (res.area && taskStatus !== "pending" && taskStatus !== "processing")) {
            await loadAllZonePages(res, task?.message || task?.stage_label || t("loadingArea"));
            break;
          }

          if (taskStatus === "failed" || taskStatus === "failure") {
            throw new Error(task?.message || t("errors.areaLoadFailed"));
          }

          if (taskStatus === "pending" || taskStatus === "processing") {
            await new Promise(resolve => setTimeout(resolve, POLL_INTERVAL));
            polls++;
          } else {
            break;
          }
        }

        if (polls >= MAX_POLLS) {
          throw new Error(t("errors.timeout"));
        }
      } catch (err) {
        setError(err instanceof Error ? err.message : t("errors.areaLoadFailed"));
      } finally {
        if (!cancelled) {
          setLoading(false);
          setProgress(null);
        }
      }
    };

    loadArea();
    return () => { cancelled = true; };
  }, [isClientReady, sensorHub, t]);

  const mapZonesData = useMemo(() => {
    if (activeLayer === "crops" && zonesData) {
      return zonesData.map(z => ({
        zoneId: z.zoneId,
        geometry: z.geometry,
        color: z.crop ? CROP_COLORS[z.crop as CropType] || "#94a3b8" : "#94a3b8",
        tooltipContent: `<div style="padding: 4px 8px;">${z.crop || "نامشخص"}</div>`,
        cultivable: !!z.crop,
        zoneInitialData: z,
      }));
    }
    return null;
  }, [activeLayer, zonesData]);

  const handleZoneClick = useCallback((zone: ZoneInitialData) => {
    setPanelOpen(true);
    setSelectedZone(null);
    cropZoningService.getZoneDetails(zone.zoneId)
      .then(setSelectedZone)
      .catch(() => setSelectedZone(null));
  }, []);

  return (
    <Box className="flex flex-col gap-6 is-full">
      <Box className="relative min-bs-[400px] rounded-xl overflow-hidden" sx={{ height: "min(60vh, 500px)" }}>
        <Box className="absolute inset-0 z-0">
          {areaGeoJson ? (
            <MapComponent
              center={[35.6892, 51.389]}
              zoom={13}
              height="100%"
              activeLayer={activeLayer}
              onZoneClick={handleZoneClick}
              initialAreaGeoJson={areaGeoJson}
              zonesData={mapZonesData}
              productLabels={Object.fromEntries(products.map(p => [p.id, p.label]))}
              readOnly
            />
          ) : (
            <Box className="flex items-center justify-center bs-full bg-action-hover" />
          )}
        </Box>

        {loading && (
          <Box className="absolute inset-0 z-[500] flex flex-col items-center justify-center gap-3 bg-white/80 dark:bg-gray-900/80" sx={{ borderRadius: 12 }}>
            <CircularProgress size={48} />
            {progress && (
              <Box className="w-full max-w-md px-8">
                <Box sx={{ fontSize: 14, fontWeight: 500, mb: 1, textAlign: "center" }}>
                  {progress.message}
                </Box>
                <LinearProgress variant="determinate" value={progress.percent} sx={{ height: 8, borderRadius: 4 }} />
                <Box sx={{ fontSize: 12, mt: 0.5, textAlign: "center", color: "text.secondary" }}>
                  {progress.percent}%
                </Box>
              </Box>
            )}
          </Box>
        )}

        {error && !loading && (
          <Box className="absolute inset-x-4 bottom-4 z-[600] rounded-xl px-4 py-3 text-sm" sx={{ backgroundColor: "error.main", color: "error.contrastText" }}>
            {error}
          </Box>
        )}

        <LayerControl activeLayer={activeLayer} onLayerChange={setActiveLayer} />
        <ZoneLegend activeLayer={activeLayer} products={products} loading={false} />
      </Box>

      <ZoneDetailPanel open={panelOpen} onClose={() => setPanelOpen(false)} zone={selectedZone} products={products} loading={false} />
      <CropZoningWeatherSection />
    </Box>
  );
}
