import React, { useState, useEffect, useCallback, useRef } from 'react';
import { FiAward, FiPercent, FiActivity, FiCheckCircle, FiClock, FiGlobe, FiLock } from 'react-icons/fi';
import { DateTime } from 'luxon';
import Tippy from '@tippyjs/react';
import 'tippy.js/dist/tippy.css';

function getStatusColor(validCert) {
  if (validCert === false) return 'bg-red-600';
  if (validCert === true) return 'bg-green-600';
  return 'bg-gray-400';
}

function getHeartbeatColor(status) {
  if (status === 1) return 'bg-green-600';   // UP
  if (status === 0) return 'bg-yellow-400';  // PENDING
  if (status === 2) return 'bg-red-600';     // DOWN
  return 'bg-gray-300';
}

function getCertBg(days) {
  if (typeof days !== 'number') return 'bg-gray-400 dark:bg-gray-600';
  if (days < 0) return 'bg-red-600 animate-pulse border-2 border-red-500 dark:bg-red-800';
  if (days < 5) return 'bg-red-600 dark:bg-red-800';
  if (days <= 15) return 'bg-yellow-400 dark:bg-yellow-500 text-gray-900';
  return 'bg-green-600 dark:bg-green-700';
}

function getCertText(days) {
  if (typeof days !== 'number') return 'Cert Exp';
  if (days < 0) return 'Cert Expired!';
  return 'Cert Exp';
}

function getAvgPingBg(avgPing) {
  if (typeof avgPing !== 'number') return 'bg-gray-300 dark:bg-gray-700';
  if (avgPing <= 80) return 'bg-green-600 text-white dark:bg-green-700 dark:text-white';
  if (avgPing <= 200) return 'bg-yellow-400 text-gray-900 dark:bg-yellow-500 dark:text-gray-900';
  return 'bg-red-600 text-white dark:bg-red-800 dark:text-white';
}

function getUptime24hBg(uptime) {
  if (typeof uptime !== 'number') return 'bg-gray-300 dark:bg-gray-700';
  if (uptime >= 99) return 'bg-green-600 text-white dark:bg-green-700 dark:text-white';
  if (uptime >= 95) return 'bg-yellow-400 text-gray-900 dark:bg-yellow-500 dark:text-gray-900';
  return 'bg-red-600 text-white dark:bg-red-800 dark:text-white';
}

function formatLocalTime(rawTime, zone = 'utc') {
  if (!rawTime) return '';
  const dt = DateTime.fromFormat(rawTime, 'yyyy-MM-dd HH:mm:ss.SSS', { zone: 'utc' });
  const localDt = dt.isValid ? dt.setZone(zone) : null;
  return localDt && localDt.isValid
    ? localDt.toFormat('dd-MM-yyyy, HH:mm:ss')
    : 'Invalid DateTime';
}

function HeartbeatPopup({ hb, userZone, monitor }) {
  const localTime = hb ? formatLocalTime(hb.time, userZone) : '';
  const utcTime = hb ? formatLocalTime(hb.time, 'utc') : '';
  return (
    <div style={{ minWidth: 220 }}>
      <div style={{ display: 'flex', alignItems: 'center', marginBottom: 4 }}>
        <FiCheckCircle color={hb.status === 1 ? 'green' : 'red'} style={{ marginRight: 6 }} />
        <b>{hb.status === 1 ? 'Up' : 'Down'}</b>
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <FiClock style={{ marginRight: 6 }} />
        Local: {localTime}
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <FiGlobe style={{ marginRight: 6 }} />
        UTC: {utcTime}
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <FiActivity style={{ marginRight: 6 }} />
        Ping: {hb.ping ?? '--'} ms
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <FiPercent style={{ marginRight: 6 }} />
        Uptime 24h: {monitor.uptime24h?.toFixed(2) ?? '--'}%
      </div>
      <div style={{ display: 'flex', alignItems: 'center' }}>
        <FiLock style={{ marginRight: 6 }} />
        Cert valid for: {monitor.certExpiryDaysRemaining ?? '--'} days
      </div>
    </div>
  );
}

export default function UptimeStatusIsland() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [openBadge, setOpenBadge] = useState({});
  const badgeRefs = useRef({});
  const [userZone, setUserZone] = useState(null);
  const [userLocale, setUserLocale] = useState(null);
  const [secondsToNextUpdate, setSecondsToNextUpdate] = useState(null);
  const [isMobile, setIsMobile] = useState(false);
  const [showLeftShadow, setShowLeftShadow] = useState(false);
  const heartbeatContainerRefs = useRef({});

  useEffect(() => {
    setUserZone(Intl.DateTimeFormat().resolvedOptions().timeZone);
    setUserLocale(navigator.language || 'en-US');
  }, []);

  // Helper: get the current 30-min window key (e.g., '2024-06-07T12:00')
  const getCurrent30MinKey = () => {
    const now = new Date();
    now.setSeconds(0, 0);
    const min = now.getMinutes();
    now.setMinutes(Math.floor(min / 30) * 30);
    return now.toISOString().slice(0, 16); // 'YYYY-MM-DDTHH:mm'
  };

  // Helper: get seconds to next 30-min mark
  const getSecondsToNext30Min = () => {
    const now = new Date();
    const minutes = now.getMinutes();
    const seconds = now.getSeconds();
    const ms = now.getMilliseconds();
    const next30 = Math.ceil((minutes + 0.01) / 30) * 30;
    let next = new Date(now);
    next.setMinutes(next30, 0, 0);
    if (next <= now) {
      next.setMinutes(next.getMinutes() + 30);
    }
    return Math.floor((next - now) / 1000);
  };

  useEffect(() => {
    const update = () => setSecondsToNextUpdate(getSecondsToNext30Min());
    update();
    const interval = setInterval(update, 1000);
    return () => clearInterval(interval);
  }, []);

  // On mount, check sessionStorage for valid cached data
  useEffect(() => {
    const cacheKey = 'uptimeStatusCache';
    const cache = sessionStorage.getItem(cacheKey);
    if (cache) {
      try {
        const { key, data: cachedData } = JSON.parse(cache);
        if (key === getCurrent30MinKey() && cachedData) {
          setData(cachedData);
          setLoading(false);
          return;
        }
      } catch {}
    }
    // If no valid cache, fetch immediately
    fetchDataImmediate();
  }, []);

  // Helper: fetch and cache immediately (used on mount if no cache)
  const fetchDataImmediate = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch('/api/uptime');
      if (!response.ok) throw new Error('Failed to fetch uptime data');
      const json = await response.json();
      setData(json);
      // Cache with current 30-min key
      const cacheKey = 'uptimeStatusCache';
      sessionStorage.setItem(cacheKey, JSON.stringify({ key: getCurrent30MinKey(), data: json }));
    } catch (err) {
      setError(err.message || 'Unknown error');
    } finally {
      setLoading(false);
    }
  }, []);

  // Scheduled fetch logic (every 30 min, update cache)
  const fetchData = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await fetch('/api/uptime');
      if (!response.ok) throw new Error('Failed to fetch uptime data');
      const json = await response.json();
      setData(json);
      // Cache with current 30-min key
      const cacheKey = 'uptimeStatusCache';
      sessionStorage.setItem(cacheKey, JSON.stringify({ key: getCurrent30MinKey(), data: json }));
    } catch (err) {
      setError(err.message || 'Unknown error');
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    const now = new Date();
    const minutes = now.getMinutes();
    const seconds = now.getSeconds();
    const ms = now.getMilliseconds();
    const next30 = Math.ceil((minutes + 0.01) / 30) * 30;
    let next = new Date(now);
    next.setMinutes(next30, 0, 0);
    if (next <= now) {
      next.setMinutes(next.getMinutes() + 30);
    }
    const msToNext = next - now;
    const timeout = setTimeout(() => {
      fetchData();
      const interval = setInterval(fetchData, 30 * 60 * 1000);
      fetchData.interval = interval;
    }, msToNext);
    return () => {
      clearTimeout(timeout);
      if (fetchData.interval) clearInterval(fetchData.interval);
    };
  }, [fetchData]);

  const toggleBadge = (monitorId, badge) => {
    setOpenBadge((prev) => ({
      ...prev,
      [monitorId]: {
        ...prev[monitorId],
        [badge]: !prev[monitorId]?.[badge],
      },
    }));
  };

  useEffect(() => {
    function handleClick(e) {
      let clickedInside = false;
      Object.values(badgeRefs.current).forEach((monitorBadges) => {
        Object.values(monitorBadges || {}).forEach((ref) => {
          if (ref && ref.current && ref.current.contains(e.target)) {
            clickedInside = true;
          }
        });
      });
      if (!clickedInside) setOpenBadge({});
    }
    document.addEventListener('mousedown', handleClick);
    return () => document.removeEventListener('mousedown', handleClick);
  }, []);

  const getBadgeRef = (monitorId, badge) => {
    if (!badgeRefs.current[monitorId]) badgeRefs.current[monitorId] = {};
    if (!badgeRefs.current[monitorId][badge]) badgeRefs.current[monitorId][badge] = React.createRef();
    return badgeRefs.current[monitorId][badge];
  };

  const totalBarSeconds = 30 * 60;
  const barValue = secondsToNextUpdate !== null ? (totalBarSeconds - secondsToNextUpdate) : 0;
  const barPercent = (barValue / totalBarSeconds) * 100;
  const barGradient = 'linear-gradient(90deg, #0161ef 0%, #0154cf 100%)';

  // Format countdown as 'X min XX sec' or 'XX sec'
  let countdownText = '--';
  if (typeof secondsToNextUpdate === 'number' && secondsToNextUpdate >= 0) {
    if (secondsToNextUpdate >= 60) {
      const min = Math.floor(secondsToNextUpdate / 60);
      const sec = secondsToNextUpdate % 60;
      countdownText = `${min} min ${sec.toString().padStart(2, '0')} sec`;
    } else {
      countdownText = `${secondsToNextUpdate} sec`;
    }
  }

  useEffect(() => {
    const checkMobile = () => setIsMobile(window.innerWidth < 640);
    checkMobile();
    window.addEventListener('resize', checkMobile);
    return () => window.removeEventListener('resize', checkMobile);
  }, []);

  // Track scroll position for left shadow on mobile heartbeat bar
  const handleHeartbeatScroll = (monitorId, e) => {
    if (!isMobile) return;
    setShowLeftShadow(e.target.scrollLeft > 0);
  };

  return (
    <div>
      <div style={{ width: '100%', margin: '0 auto', maxWidth: 1600, padding: '24px 0 8px 0' }}>
        <div
          style={{
            height: 16,
            borderRadius: 9999,
            background: '#e5e7eb',
            position: 'relative',
            overflow: 'hidden',
            boxShadow: '0 2px 8px rgba(30,41,59,0.08)',
          }}
        >
          <div
            style={{
              width: `calc(${barPercent}% + 2px)`,
              height: '100%',
              background: barGradient,
              borderRadius: 9999,
              position: 'absolute',
              left: 0,
              top: 0,
              zIndex: 2,
              transition: 'width 0.5s cubic-bezier(0.4,0,0.2,1)',
              boxShadow: '0 1px 4px rgba(59,130,246,0.10)',
              pointerEvents: 'none',
            }}
          ></div>
        </div>
        <div style={{ textAlign: 'center', color: '#a3a3a3', fontWeight: 600, marginTop: 8, fontSize: 18 }}>
          Next update in {countdownText}
        </div>
      </div>
      <div className="grid gap-10 md:grid-cols-2">
        {loading ? (
          <div className="text-center text-gray-500 dark:text-gray-400">Loading...</div>
        ) : error ? (
          <div className="text-center text-red-500 dark:text-red-400">{error}</div>
        ) : data && data.publicGroupList && data.publicGroupList.length > 0 ? (
          data.publicGroupList.map((group) => (
            <section key={group.id} className="bg-white/40 dark:bg-slate-800/40 backdrop-blur-md border border-gray-200 dark:border-slate-800 rounded-2xl shadow-lg p-8 flex flex-col">
              <h2 className="text-2xl font-bold mb-6 text-gray-900 dark:text-white">{group.name}</h2>
              <ul className="space-y-6">
                {group.monitorList.map((monitor) => (
                  <li key={monitor.id} className="flex flex-col gap-2 rounded-xl px-5 py-4 shadow border border-gray-200 dark:border-gray-700">
                    {isMobile ? (
                      <>
                        <div className="flex items-center min-w-0 mb-2">
                          <span className={`inline-block w-3 h-3 rounded-full ${getStatusColor(monitor.validCert)} mr-2`}></span>
                          <span className="font-semibold text-lg text-gray-800 dark:text-gray-100 truncate">{monitor.name}</span>
                        </div>
                        <div className="flex flex-row items-center justify-between w-full gap-3">
                          {monitor.certExpiryDaysRemaining !== undefined && (
                            <span
                              ref={getBadgeRef(monitor.id, 'cert')}
                              className={`px-2 py-1 rounded-full text-xs font-medium flex items-center justify-center ${getCertBg(monitor.certExpiryDaysRemaining)}`}
                              title={monitor.certExpiryDaysRemaining < 0 ? 'Certificate expired!' : `Certificate expires in ${monitor.certExpiryDaysRemaining} days`}
                              onClick={() => toggleBadge(monitor.id, 'cert')}
                              style={{ cursor: 'pointer', position: 'relative' }}
                            >
                              <FiAward className="w-4 h-4" />
                              {openBadge[monitor.id]?.cert && (
                                <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                  {monitor.certExpiryDaysRemaining < 0
                                    ? 'Expired!'
                                    : `Expires in ${monitor.certExpiryDaysRemaining} days`}
                                </span>
                              )}
                            </span>
                          )}
                          {monitor.avgPing !== undefined && (
                            <span
                              ref={getBadgeRef(monitor.id, 'avgPing')}
                              className={`px-2 py-1 rounded-full text-xs font-medium flex items-center justify-center ${getAvgPingBg(monitor.avgPing)}`}
                              onClick={() => toggleBadge(monitor.id, 'avgPing')}
                              style={{ cursor: 'pointer', position: 'relative' }}
                            >
                              <FiActivity className="w-4 h-4" />
                              {openBadge[monitor.id]?.avgPing && (
                                <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                  {monitor.avgPing} ms
                                </span>
                              )}
                            </span>
                          )}
                          {monitor.uptime24h !== undefined && (
                            <span
                              ref={getBadgeRef(monitor.id, 'uptime')}
                              className={`px-2 py-1 rounded-full text-xs font-medium flex items-center justify-center ${getUptime24hBg(monitor.uptime24h)}`}
                              onClick={() => toggleBadge(monitor.id, 'uptime')}
                              style={{ cursor: 'pointer', position: 'relative' }}
                            >
                              <FiPercent className="w-4 h-4" />
                              {openBadge[monitor.id]?.uptime && (
                                <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                  {monitor.uptime24h.toFixed(1)}%
                                </span>
                              )}
                            </span>
                          )}
                        </div>
                      </>
                    ) : (
                      <div className="grid grid-cols-5 items-center w-full gap-2">
                        <div className="flex items-center min-w-0 col-span-2">
                          <span className={`inline-block w-3 h-3 rounded-full ${getStatusColor(monitor.validCert)} mr-2`}></span>
                          <span className="font-semibold text-lg text-gray-800 dark:text-gray-100 truncate">{monitor.name}</span>
                        </div>
                        <div className="flex flex-col items-center col-span-1 relative">
                          {monitor.certExpiryDaysRemaining !== undefined && (
                            <>
                              <span className={`hidden sm:inline px-2 py-0 rounded-full text-xs font-medium text-white ${getCertBg(monitor.certExpiryDaysRemaining)}`}
                                title={monitor.certExpiryDaysRemaining < 0 ? 'Certificate expired!' : `Certificate expires in ${monitor.certExpiryDaysRemaining} days`}>
                                {getCertText(monitor.certExpiryDaysRemaining)}
                              </span>
                              <span
                                ref={getBadgeRef(monitor.id, 'cert')}
                                className={`sm:hidden px-2 py-0 rounded-full text-xs font-medium flex items-center justify-center ${getCertBg(monitor.certExpiryDaysRemaining)}`}
                                title={monitor.certExpiryDaysRemaining < 0 ? 'Certificate expired!' : `Certificate expires in ${monitor.certExpiryDaysRemaining} days`}
                                onClick={() => toggleBadge(monitor.id, 'cert')}
                                style={{ cursor: 'pointer', position: 'relative' }}
                              >
                                <FiAward className="w-4 h-4" />
                                {openBadge[monitor.id]?.cert && (
                                  <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                    {monitor.certExpiryDaysRemaining < 0
                                      ? 'Expired!'
                                      : `Expires in ${monitor.certExpiryDaysRemaining} days`}
                                  </span>
                                )}
                              </span>
                            </>
                          )}
                        </div>
                        <div className="flex flex-col items-center col-span-1 relative">
                          {monitor.avgPing !== undefined && (
                            <>
                              <span className={`hidden sm:inline px-2 py-0 rounded-full text-xs font-medium ${getAvgPingBg(monitor.avgPing)}`}
                                title={`Avg. response: ${monitor.avgPing} ms`}>
                                Avg: {monitor.avgPing} ms
                              </span>
                              <span
                                ref={getBadgeRef(monitor.id, 'avgPing')}
                                className={`sm:hidden px-2 py-0 rounded-full text-xs font-medium flex items-center justify-center ${getAvgPingBg(monitor.avgPing)}`}
                                onClick={() => toggleBadge(monitor.id, 'avgPing')}
                                style={{ cursor: 'pointer', position: 'relative' }}
                              >
                                <FiActivity className="w-4 h-4" />
                                {openBadge[monitor.id]?.avgPing && (
                                  <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                    {monitor.avgPing} ms
                                  </span>
                                )}
                              </span>
                            </>
                          )}
                        </div>
                        <div className="flex flex-col items-center col-span-1 relative">
                          {monitor.uptime24h !== undefined && (
                            <>
                              <span className={`hidden sm:inline px-2 py-0 rounded-full text-xs font-medium ${getUptime24hBg(monitor.uptime24h)}`}> 
                                24h: {monitor.uptime24h.toFixed(1)}%
                              </span>
                              <span
                                ref={getBadgeRef(monitor.id, 'uptime')}
                                className={`sm:hidden px-2 py-0 rounded-full text-xs font-medium flex items-center justify-center ${getUptime24hBg(monitor.uptime24h)}`}
                                onClick={() => toggleBadge(monitor.id, 'uptime')}
                                style={{ cursor: 'pointer', position: 'relative' }}
                              >
                                <FiPercent className="w-4 h-4" />
                                {openBadge[monitor.id]?.uptime && (
                                  <span className="absolute bottom-full left-1/2 -translate-x-1/2 mb-2 z-20 bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 rounded-lg shadow-lg px-3 py-2 text-xs whitespace-nowrap border border-gray-200 dark:border-gray-700">
                                    {monitor.uptime24h.toFixed(1)}%
                                  </span>
                                )}
                              </span>
                            </>
                          )}
                        </div>
                      </div>
                    )}
                    {monitor.heartbeatHistory && monitor.heartbeatHistory.length > 0 && (
                      <div
                        className={`heartbeat-history-container ${isMobile ? 'mobile' : 'desktop'} bg-gray-200 dark:bg-slate-700 rounded px-2 py-1 w-full`}
                        style={{
                          overflowX: isMobile ? 'auto' : 'visible',
                          WebkitOverflowScrolling: 'touch',
                          width: '100%',
                          maxWidth: '100vw',
                          minWidth: 0,
                          position: 'relative',
                        }}
                        ref={el => { if (el && isMobile) heartbeatContainerRefs.current[monitor.id] = el; }}
                        onScroll={e => handleHeartbeatScroll(monitor.id, e)}
                      >
                        {/* Left shadow overlay for mobile, only if scrolled */}
                        {isMobile && showLeftShadow && (
                          <div className="heartbeat-left-shadow" />
                        )}
                        <div
                          className={isMobile ? 'grid-cols-10' : 'grid-cols-40'}
                          style={{
                            display: 'grid',
                            gridTemplateColumns: `repeat(${isMobile ? 10 : 40}, 1fr)`,
                            width: '100%',
                            minWidth: 0,
                            gap: '2px',
                          }}
                        >
                          {(() => {
                            const hbArr = monitor.heartbeatHistory ?? [];
                            const slice = isMobile ? hbArr.slice(-10) : hbArr.slice(-40);
                            // Show most recent first (left), so reverse the slice
                            const ordered = slice;
                            return ordered.map((hb, i) => (
                              <Tippy
                                key={i}
                                content={<HeartbeatPopup hb={hb} userZone={userZone} monitor={monitor} />}
                                placement="top"
                                animation="shift-away"
                                theme="devnet"
                                delay={[0, 0]}
                              >
                                <span
                                  className={`w-full h-4 rounded-sm ${hb ? getHeartbeatColor(hb.status) : 'bg-gray-400 dark:bg-gray-600'} block`}
                                  style={{ cursor: 'pointer' }}
                                ></span>
                              </Tippy>
                            ));
                          })()}
                        </div>
                      </div>
                    )}
                  </li>
                ))}
              </ul>
            </section>
          ))
        ) : (
          <div className="text-center text-gray-500 dark:text-gray-400">No status data available</div>
        )}
      </div>
      <style>{`
        .grid-cols-40 {
          display: grid;
          grid-template-columns: repeat(40, minmax(0, 1fr));
        }
        .grid-cols-10 {
          display: grid;
          grid-template-columns: repeat(10, 1fr);
        }
        .heartbeat-history-container.mobile {
          overflow-x: auto;
          -webkit-overflow-scrolling: touch;
          min-width: 0;
          width: 100%;
          position: relative;
          max-width: 100vw;
        }
        .heartbeat-left-shadow {
          position: absolute;
          left: 0;
          top: 0;
          bottom: 0;
          width: 24px;
          pointer-events: none;
          z-index: 10;
          background: linear-gradient(to right, rgba(0,0,0,0.18) 0%, rgba(0,0,0,0.00) 100%);
        }
      `}</style>
    </div>
  );
} 