'use client';

import { useState, useEffect, useMemo, useRef } from 'react';
import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import SiteSelector from '@/components/dashboards/SiteSelector';
import SiteStatus from '@/components/dashboards/SiteStatus';
import DashboardLayout from './dashlayout';
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
import dynamic from 'next/dynamic';
import { fetchPowerTimeseries } from '@/app/utils/api';
import KpiTop from '@/components/dashboards/kpitop';
import KpiBottom from '@/components/dashboards/kpibottom';
import { formatAddress } from '@/app/utils/formatAddress';
import { formatCrmTimestamp } from '@/app/utils/datetime';
import LoggingControlCard from '@/components/dashboards/LoggingControl';
import { buildExportUrl, getFilenameFromCD } from "@/utils/export";

const EnergyLineChart = dynamic(() => import('@/components/dashboards/EnergyLineChart'), { ssr: false });
const MonthlyBarChart  = dynamic(() => import('@/components/dashboards/MonthlyBarChart'), { ssr: false });

type MonthlyKPI = {
  site: string; month: string;
  yield_kwh: number | null; consumption_kwh: number | null; grid_draw_kwh: number | null;
  efficiency: number | null; peak_demand_kw: number | null;
  avg_power_factor: number | null; load_factor: number | null;
  error?: string;
};

type CrmProject = {
  name: string;                  // e.g. PROJ-0008  <-- use as siteId
  project_name: string;
  status?: string;
  percent_complete?: number | null;
  owner?: string | null;
  modified?: string | null;
  customer?: string | null;
  project_type?: string | null;
  custom_address?: string | null;
  custom_email?: string | null;
  custom_mobile_phone_no?: string | null;
};

const API = process.env.NEXT_PUBLIC_FASTAPI_URL;

// Adjust this to your FastAPI route
const START_LOGGING_ENDPOINT = (siteId: string) =>
  `${API}/logging/start?site=${encodeURIComponent(siteId)}`;

// helper to build ISO strings with +08:00
const withTZ = (d: Date) => {
  const yyyyMMdd = d.toISOString().split('T')[0];
  return {
    start: `${yyyyMMdd}T00:00:00+08:00`,
    end:   `${yyyyMMdd}T23:59:59+08:00`,
  };
};

const AdminDashboard = () => {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const [authChecked, setAuthChecked] = useState(false);

  // --- load CRM projects dynamically ---
  const [sites, setSites] = useState<CrmProject[]>([]);
  const [sitesLoading, setSitesLoading] = useState(true);
  const [sitesError, setSitesError] = useState<unknown>(null);
  // near other refs
  const loggingRef = useRef<HTMLDivElement | null>(null);

  const API = process.env.NEXT_PUBLIC_FASTAPI_URL || 'http://127.0.0.1:8000';

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

  const checkAuth = async () => {
    try {
      const res = await fetch(`${API}/auth/me`, {
        credentials: 'include',
        cache: 'no-store',
      });

      if (!res.ok) {
        router.replace('/login');
        return;
      }

      const user = await res.json().catch(() => null);
      if (!user?.id) {
        router.replace('/login');
        return;
      }
      // authenticated
    } catch {
      router.replace('/login');
      return;
    } finally {
      if (!cancelled) setAuthChecked(true);
    }
  };

  checkAuth();
  return () => { cancelled = true; };
}, [router, API]);

  

  useEffect(() => {
    setSitesLoading(true);
    fetch(`${API}/crm/projects?limit=0`)
      .then(r => r.json())
      .then(json => setSites(json?.data ?? []))
      .catch(setSitesError)
      .finally(() => setSitesLoading(false));
  }, []);

  // The canonical siteId is the CRM Project "name" (e.g., PROJ-0008)
  const siteParam = searchParams?.get('site') || null;
  const [selectedSiteId, setSelectedSiteId] = useState<string | null>(siteParam);

  // Keep query param <-> state in sync
  useEffect(() => {
    if ((siteParam || null) !== selectedSiteId) {
      setSelectedSiteId(siteParam);
    }
  }, [siteParam]); // eslint-disable-line

  // Default to the first site when loaded
  useEffect(() => {
    if (!selectedSiteId && sites.length) {
      setSelectedSiteId(sites[0].name);
      router.replace(`${pathname}?site=${encodeURIComponent(sites[0].name)}`);
    }
  }, [sites, selectedSiteId, pathname, router]);

  // Current selected CRM project
  const selectedProject: CrmProject | null = useMemo(
    () => sites.find(s => s.name === selectedSiteId) ?? null,
    [sites, selectedSiteId]
  );

  // declare currentMonth BEFORE it’s used
  const currentMonth = useMemo(() => new Date().toISOString().slice(0, 7), []);

  // --- Time-series state ---
  const [timeSeriesData, setTimeSeriesData] = useState<{
    consumption: { time: string; value: number }[];
    generation: { time: string; value: number }[];
  }>({ consumption: [], generation: [] });

  // data-availability flags
  const [hasAnyData, setHasAnyData] = useState(false);   // historical window
  const [hasTodayData, setHasTodayData] = useState(false);
  const [isLogging, setIsLogging] = useState(false);
  const [startError, setStartError] = useState<string | null>(null);

  // Fetch today’s timeseries for selected siteId
  useEffect(() => {
    if (!selectedSiteId) return;

    const fetchToday = async () => {
      const { start, end } = withTZ(new Date());

      try {
        const raw = await fetchPowerTimeseries(selectedSiteId, start, end);
        const consumption = raw.consumption.map((d: any) => ({ time: d.time, value: d.value }));
        const generation  = raw.generation.map((d: any) => ({ time: d.time, value: d.value }));
        setTimeSeriesData({ consumption, generation });

        const anyToday = (consumption?.length ?? 0) > 0 || (generation?.length ?? 0) > 0;
        setHasTodayData(anyToday);
      } catch (error) {
        console.error('Failed to fetch power time series:', error);
        setHasTodayData(false);
      }
    };

    fetchToday();
  }, [selectedSiteId]);

  // Check historical data (last 30 days) → controls empty state
  useEffect(() => {
    if (!selectedSiteId) return;

    const fetchHistorical = async () => {
      try {
        const endDate = new Date();
        const startDate = new Date();
        startDate.setDate(endDate.getDate() - 30);

        const startISO = `${startDate.toISOString().split('T')[0]}T00:00:00+08:00`;
        const endISO   = `${endDate.toISOString().split('T')[0]}T23:59:59+08:00`;

        const raw = await fetchPowerTimeseries(selectedSiteId, startISO, endISO);
        const anyHistorical =
          (raw?.consumption?.length ?? 0) > 0 ||
          (raw?.generation?.length ?? 0) > 0;

        setHasAnyData(anyHistorical);
      } catch (e) {
        console.error('Failed to check historical data:', e);
        setHasAnyData(false);
      }
    };

    fetchHistorical();
  }, [selectedSiteId]);

  // --- KPI monthly ---
  const [kpi, setKpi] = useState<MonthlyKPI | null>(null);

  useEffect(() => {
    if (!selectedSiteId) return;
    const url = `${API}/kpi/monthly?site=${encodeURIComponent(selectedSiteId)}&month=${currentMonth}`;
    fetch(url).then(r => r.json()).then(setKpi).catch(console.error);
  }, [selectedSiteId, currentMonth]);

  // derived values with safe fallbacks
  const yieldKwh       = kpi?.yield_kwh ?? 0;
  const consumptionKwh = kpi?.consumption_kwh ?? 0;
  const gridDrawKwh    = kpi?.grid_draw_kwh ?? Math.max(0, consumptionKwh - yieldKwh);
  const efficiencyPct  = (kpi?.efficiency ?? 0) * 100;
  const powerFactor    = kpi?.avg_power_factor ?? 0;
  const loadFactor     = (kpi?.load_factor ?? 0);

  // Update URL when site is changed manually (expects a siteId/Project.name)
  const handleSiteChange = (newSiteId: string) => {
    setSelectedSiteId(newSiteId);
    const newUrl = `${pathname}?site=${encodeURIComponent(newSiteId)}`;
    router.push(newUrl);
    // reset flags when switching
    setHasAnyData(false);
    setHasTodayData(false);
    setIsLogging(false);
    setStartError(null);
  };

  const locationFormatted = useMemo(() => {
    const raw = selectedProject?.custom_address ?? '';
    if (!raw) return 'N/A';
    return formatAddress(raw).multiLine;
  }, [selectedProject?.custom_address]);

  const lastSyncFormatted = useMemo(
    () => formatCrmTimestamp(selectedProject?.modified, { includeSeconds: true }),
    [selectedProject?.modified]
  );

  // Adapt CRM project -> SiteStatus props
  const currentSiteDetails = {
    location: locationFormatted,
    inverterProvider: selectedProject?.project_type || 'N/A',
    emergencyContact:
      selectedProject?.custom_mobile_phone_no ||
      selectedProject?.custom_email ||
      selectedProject?.customer ||
      'N/A',
    lastSyncTimestamp: lastSyncFormatted || 'N/A',
  };

  const energyChartRef = useRef<HTMLDivElement | null>(null);
  const monthlyChartRef = useRef<HTMLDivElement | null>(null);

  const handlePDFExport = async () => {
    const doc = new jsPDF('p', 'mm', 'a4');
    const chartRefs = [
      { ref: energyChartRef,  title: 'Energy Line Chart' },
      { ref: monthlyChartRef, title: 'Monthly Energy Yield' }
    ];

    let yOffset = 10;

    for (const chart of chartRefs) {
      if (!chart.ref.current) continue;
      const canvas = await html2canvas(chart.ref.current, { scale: 2 });
      const imgData = canvas.toDataURL('image/png');
      const imgProps = doc.getImageProperties(imgData);
      const pdfWidth = doc.internal.pageSize.getWidth() - 20;
      const imgHeight = (imgProps.height * pdfWidth) / imgProps.width;

      doc.setFontSize(14);
      doc.text(chart.title, 10, yOffset);
      yOffset += 6;

      if (yOffset + imgHeight > doc.internal.pageSize.getHeight()) {
        doc.addPage();
        yOffset = 10;
      }

      doc.addImage(imgData, 'PNG', 10, yOffset, pdfWidth, imgHeight);
      yOffset += imgHeight + 10;
    }

    doc.save('dashboard_charts.pdf');
  };

  // Start logging then poll for data until it shows up
  const startLogging = async () => {
    if (!selectedSiteId) return;
    setIsLogging(true);
    setStartError(null);

    try {
      const resp = await fetch(START_LOGGING_ENDPOINT(selectedSiteId), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
      });

      if (!resp.ok) {
        const text = await resp.text();
        throw new Error(text || `Failed with status ${resp.status}`);
      }

      // Poll for data for up to ~45s (15 tries x 3s)
      for (let i = 0; i < 15; i++) {
        const today = new Date();
        const { start, end } = withTZ(today);

        try {
          const raw = await fetchPowerTimeseries(selectedSiteId, start, end);
          const consumption = raw.consumption ?? [];
          const generation  = raw.generation ?? [];
          if ((consumption.length ?? 0) > 0 || (generation.length ?? 0) > 0) {
            setHasAnyData(true);     // site now has data
            setHasTodayData(true);   // and today has data too
            break;
          }
  } catch {
          // ignore and keep polling
        }
        await new Promise(r => setTimeout(r, 3000));
      }
    } catch (e: any) {
      setStartError(e?.message ?? 'Failed to start logging');
      setIsLogging(false);
    }
  };

  // helpers
// helpers
const ymd = (d: Date) => d.toISOString().slice(0, 10);
const excelUrl = (site: string, device: string, fn: 'grid' | 'solar', dateYMD: string) =>
  `${API}/excel-fs/${encodeURIComponent(site)}/${encodeURIComponent(device)}/${fn}/${dateYMD}.xlsx`;

// popup state
const [isDownloadOpen, setIsDownloadOpen] = useState(false);
const [meter, setMeter] = useState('01');                         // ADW300 device id
const [fn, setFn] = useState<'grid' | 'solar'>('grid');           // which function
const [downloadDate, setDownloadDate] = useState(ymd(new Date())); // YYYY-MM-DD
const [downloading, setDownloading] = useState(false);

// action
// util: parse filename from Content-Disposition
function getFilenameFromCD(h: string | null): string | null {
  if (!h) return null;
  // filename*=UTF-8''name.ext  (RFC 5987)
  const star = /filename\*\s*=\s*([^']*)''([^;]+)/i.exec(h);
  if (star && star[2]) return decodeURIComponent(star[2]);

  // filename="name.ext" or filename=name.ext
  const plain = /filename\s*=\s*("?)([^";]+)\1/i.exec(h);
  if (plain && plain[2]) return plain[2];

  return null;
}

const downloadExcel = async () => {
  if (!selectedProject) return;
  try {
    setDownloading(true);

    // Prefer the simple day-based export
    const url = buildExportUrl({
      baseUrl: process.env.NEXT_PUBLIC_FASTAPI_URL,
      site: selectedProject.name,
      suffix: fn,
      serial: meter?.trim() || undefined,
      day: downloadDate, // "YYYY-MM-DD"
    });


    const resp = await fetch(url, { credentials: "include" });

    if (!resp.ok) {
      // server might return JSON error; try to surface it nicely
      const ctype = resp.headers.get("Content-Type") || "";
      let msg = `HTTP ${resp.status}`;
      if (ctype.includes("application/json")) {
        const j = await resp.json().catch(() => null);
        if (j?.detail) msg = String(j.detail);
      } else {
        const t = await resp.text().catch(() => "");
        if (t) msg = t;
      }
      throw new Error(msg);
    }

    const blob = await resp.blob();

    // 1) use server-provided filename if present
    const cd = resp.headers.get("Content-Disposition");
    let downloadName = getFilenameFromCD(cd);

    // 2) client-side fallback (date-only as requested)
    if (!downloadName) {
      const serialPart = meter?.trim() ? meter.trim() : "ALL";
      downloadName = `${selectedProject.name}_${serialPart}_${fn}_${downloadDate}.xlsx`;
    }

    const a = document.createElement("a");
    const href = URL.createObjectURL(blob);
    a.href = href;
    a.download = downloadName;
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(href);
    setIsDownloadOpen(false);
  } catch (e: any) {
    alert(`Download failed: ${e?.message ?? e}`);
  } finally {
    setDownloading(false);
  }
};



  // ---------- RENDER ----------
  if (!authChecked) {
    return <div>Checking authentication…</div>;
  }
  
  if (sitesLoading) {
    return (
      <DashboardLayout>
        <div className="px-6">Loading sites…</div>
      </DashboardLayout>
    );
  }
  if (sitesError) {
    return (
      <DashboardLayout>
        <div className="px-6 text-red-600">Failed to load sites from CRM.</div>
      </DashboardLayout>
    );
  }
  if (!selectedProject) {
    return (
      <DashboardLayout>
        <div className="px-6">No site selected.</div>
      </DashboardLayout>
    );
  }

  // Build selector options from CRM
  const siteOptions = sites.map(s => ({
    label: s.project_name || s.name,
    value: s.name,
  }));

  return (
    <DashboardLayout>
      <div className="px-3 space-y-6 w-full max-w-screen-3xl mx-auto">
        <h1 className="text-lg font-semibold dark:text-white">Admin Dashboard</h1>

        {/* Selector + status */}
        <div className="grid grid-cols-1 gap-6 w-full min-w-0">
          <div className="space-y-4 w-full min-w-0">
            <SiteSelector
              options={siteOptions}
              selectedValue={selectedSiteId!}
              onChange={handleSiteChange}
            />

            <SiteStatus
              selectedSite={selectedProject.project_name || selectedProject.name}
              siteId={selectedProject.name}
              location={currentSiteDetails.location}
              inverterProvider={currentSiteDetails.inverterProvider}
              emergencyContact={currentSiteDetails.emergencyContact}
              lastSyncTimestamp={currentSiteDetails.lastSyncTimestamp}
            />
            

          </div>
        </div>

        {/* Small dark yellow banner when there is ZERO historical data */}
        {!hasAnyData && (
          <div className="rounded-lg border border-amber-400/40 bg-rtyellow-300/20 px-4 py-3 text-amber-600 dark:text-amber-100 flex flex-wrap items-center gap-3">
            <span className="font-semibold text-black/85 dark:text-white/85">No data yet.</span>
            <span className="opacity-95">Enter the meter number and click <span className="font-semibold text-black/85 dark:text-white/85">Start</span> to begin streaming.
            </span>

            {startError && <div className="basis-full text-sm text-red-300">{startError}</div>}
          </div>
        )}

        <div ref={loggingRef}>
          <LoggingControlCard
            siteId={selectedProject.name}
            projectLabel={selectedProject.project_name || selectedProject.name}
            className="w-full"
          />
        </div>

        {/* Render the rest only if there is *any* data */}
        {hasAnyData && (
          <>
            {/* Tiny banner if today is empty but historical exists */}
            {!hasTodayData && (
              <div className="rounded-lg border border-amber-300/50 bg-amber-50 dark:bg-amber-900/20 px-4 py-2 text-amber-800 dark:text-amber-200">
                No data yet today — charts may be blank until new points arrive.
              </div>
            )}
            

            {/* TOP 3 CARDS */}
            <div className="space-y-4">
              <KpiTop
                yieldKwh={yieldKwh}
                consumptionKwh={consumptionKwh}
                gridDrawKwh={gridDrawKwh}
              />
            </div>

            <div ref={energyChartRef} className="pb-5">
              <EnergyLineChart siteId={selectedProject.name} />
            </div>

            {/* BOTTOM 3 PANELS */}
            <KpiBottom
              efficiencyPct={efficiencyPct}
              powerFactor={powerFactor}
              loadFactor={loadFactor}
              middle={
                <div ref={monthlyChartRef} className="transform scale-90 origin-top">
                  <MonthlyBarChart siteId={selectedProject.name} />
                </div>
              }
              right={
                <div className="flex items-center justify-center w-full px-3 text-center">
                  <div className="text-3xl font-semibold">
                    {(kpi?.peak_demand_kw ?? 0).toFixed(2)} kW
                  </div>
                </div>
              }
            />

            <div className="flex flex-col md:flex-row gap-4 justify-center">
              <button onClick={handlePDFExport} className="text-sm lg:text-lg btn-primary">
                Export Chart Images to PDF
              </button>

              <button
                onClick={() => setIsDownloadOpen(true)}
                className="text-sm lg:text-lg btn-primary"
              >
                Download Excel Log
              </button>
            </div>

          </>
        )}

        {isDownloadOpen && (
  <div
    className="fixed inset-0 z-50 flex items-center justify-center"
    aria-modal="true"
    role="dialog"
    onKeyDown={(e) => e.key === 'Escape' && setIsDownloadOpen(false)}
  >
    {/* Backdrop */}
    <div
      className="absolute inset-0 bg-black/50"
      onClick={() => setIsDownloadOpen(false)}
    />

    {/* Modal */}
    <div className="relative w-full max-w-lg mx-4 rounded-2xl bg-white dark:bg-rtgray-800 shadow-2xl">
      <div className="p-5 sm:p-6 border-b border-black/5 dark:border-white/10">
        <h3 className="text-lg font-semibold text-black/90 dark:text-white">
          Download Excel Log
        </h3>
        <p className="mt-1 text-sm text-black/60 dark:text-white/60">
          Choose device, function, and date to export the .xlsx generated by the logger.
        </p>
      </div>

      <div className="p-5 sm:p-6 space-y-5">
        {/* Site (read-only preview) */}
        <div>
          <label className="block text-sm opacity-80 mb-1 dark:text-white">Site</label>
          <div className="px-3 py-2 rounded-lg bg-black/5 dark:bg-white/5 text-sm truncate dark:text-white">
            {selectedProject?.project_name || selectedProject?.name}
          </div>
        </div>

        {/* Device + Function */}
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
          <div>
            <label className="block text-sm opacity-80 mb-1 dark:text-white">Meter (Device)</label>
            <input
              value={meter}
              onChange={(e) => setMeter(e.target.value)}
              placeholder="01"
              className="input input-bordered w-full pl-2 rounded-lg"
            />
            <p className="mt-1 text-xs opacity-70 dark:text-white">
              Matches topic: <code>ADW300/&lt;site&gt;/<b>{meter || '01'}</b>/…</code>
            </p>
          </div>

          <div>
            <label className="block text-sm opacity-80 mb-1 dark:text-white">Function</label>
            <div className="flex rounded-xl overflow-hidden border border-black/10 dark:border-white/10">
              <button
                type="button"
                onClick={() => setFn('grid')}
                className={`flex-1 px-3 py-2 text-sm ${
                  fn === 'grid'
                    ? 'bg-rtyellow-200 text-black'
                    : 'bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 dark:text-white'
                }`}
              >
                Grid
              </button>
              <button
                type="button"
                onClick={() => setFn('solar')}
                className={`flex-1 px-3 py-2 text-sm ${
                  fn === 'solar'
                    ? 'bg-rtyellow-200 text-black'
                    : 'bg-black/5 dark:bg-white/5 hover:bg-black/10 dark:hover:bg-white/10 dark:text-white'
                }`}
              >
                Solar
              </button>
            </div>
          </div>
        </div>

        {/* Date + quick picks */}
        <div>
          <label className="block text-sm opacity-80 mb-1 dark:text-white">Date</label>
          <div className="flex items-center gap-3">
            <input
              type="date"
              value={downloadDate}
              onChange={(e) => setDownloadDate(e.target.value)}
              className="input input-bordered w-48 pl-2 rounded-lg"
            />
            <div className="flex gap-2">
              <button
                type="button"
                className="px-3 py-1 rounded-full text-xs border border-black/10 dark:border-white/15 hover:bg-black/5 dark:hover:bg-white/10 dark:text-white"
                onClick={() => setDownloadDate(ymd(new Date()))}
              >
                Today
              </button>
              <button
                type="button"
                className="px-3 py-1 rounded-full text-xs border border-black/10 dark:border-white/15 hover:bg-black/5 dark:hover:bg:white/10 dark:text-white"
                onClick={() => {
                  const d = new Date();
                  d.setDate(d.getDate() - 1);
                  setDownloadDate(ymd(d));
                }}
              >
                Yesterday
              </button>
            </div>
          </div>
        </div>
      </div>

      {/* Footer */}
      <div className="p-5 sm:p-6 flex justify-end gap-3 border-t border-black/5 dark:border-white/10">
        <button
          type="button"
          className="btn btn-primary bg-red-500 hover:bg-red-600 border-transparent"
          onClick={() => setIsDownloadOpen(false)}
          disabled={downloading}
        >
          Cancel
        </button>
        <button
          type="button"
          className="btn btn-primary border-transparent"
          onClick={downloadExcel}
          disabled={downloading || !meter || !downloadDate}
        >
          {downloading ? 'Preparing…' : 'Download'}
        </button>
      </div>
    </div>
  </div>
)}

      </div>
    </DashboardLayout>
  );
};

export default AdminDashboard;
