/**
 * Instances Management Page
 * Display and manage all Helm instances across clusters
 */
import React, { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { Package, RefreshCw, Boxes, Server } from "lucide-react";
import { listClusters, listInstances, deleteInstance, updateInstance } from "@/api";
import type { ClusterResponse, InstanceResponse, UpdateInstanceRequest } from "@/api";
import type { Cluster, Instance } from "@/core/types";
import {
  PageHeader,
  DropdownSelect,
  Button,
  LoadingState,
  ErrorState,
  EmptyState,
} from "@/shared/components";
import { useToast } from "@/shared";
import { InstanceErrors, SuccessMessages, formatApiError } from "@/shared/utils";
import { InstanceCard } from "../components/InstanceCard";
import { ModifyModal } from "../components/ModifyModal";
import { EntriesModal } from "../components/EntriesModal";
import { DiagnosticsModal } from "../components/DiagnosticsModal";
import { globalCache } from "@/shared/services/artifact-cache";

const AUTO_REFRESH_INTERVAL_MS = 30000;

type LoadDataMode = "initial" | "manual" | "auto";

interface LoadDataOptions {
  skipCache?: boolean;
  mode?: LoadDataMode;
}

const InstancesManagementPage: React.FC = () => {
  const { success, error: toastError, info: toastInfo } = useToast();

  const [clusters, setClusters] = useState<ClusterResponse[]>([]);
  const [instancesByCluster, setInstancesByCluster] = useState<
    Map<string, InstanceResponse[]>
  >(new Map());
  const [instanceTotals, setInstanceTotals] = useState<Map<string, number>>(new Map());
  const [selectedCluster, setSelectedCluster] = useState<string>("all");
  const [loading, setLoading] = useState(true);
  const [refreshing, setRefreshing] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Modals
  const [modifyInstance, setModifyInstance] = useState<Instance | null>(null);
  const [entriesInstance, setEntriesInstance] = useState<Instance | null>(null);
  const [diagnosticsInstance, setDiagnosticsInstance] = useState<Instance | null>(null);

  // 核心数据加载函数 - 使用全局缓存
  const loadDataCore = useCallback(async (options: LoadDataOptions = {}) => {
    const { skipCache = false, mode = "initial" } = options;
    const shouldShowLoading = mode === "initial";
    const shouldShowRefreshing = mode === "manual";

    if (shouldShowRefreshing) {
      setRefreshing(true);
    } else if (shouldShowLoading) {
      setLoading(true);
    }
    setError(null);
    try {
      // Load clusters with cache
      let clustersData: ClusterResponse[];
      if (!skipCache) {
        const cachedClusters = globalCache.get<ClusterResponse[]>('clusters');
        if (cachedClusters) {
          console.log('[InstancesManagementPage] Using cached clusters');
          clustersData = cachedClusters;
        } else {
          clustersData = await listClusters();
          globalCache.set('clusters', clustersData);
        }
      } else {
        clustersData = await listClusters();
        globalCache.set('clusters', clustersData);
      }
      const validClusters = clustersData.filter(
        (cluster): cluster is ClusterResponse & { id: string } =>
          typeof cluster.id === "string" && cluster.id.length > 0
      );
      setClusters(validClusters);

      // Load instances for each cluster with cache
      const instancesMap = new Map<string, InstanceResponse[]>();
      const totalsMap = new Map<string, number>();
      for (const cluster of validClusters) {
        const clusterId = cluster.id;
        try {
          let normalized: NormalizedInstanceList;
          if (!skipCache) {
            const cachedInstances = globalCache.get<unknown>('instances', clusterId);
            if (cachedInstances) {
              normalized = normalizeInstanceList(cachedInstances);
              console.log(`[InstancesManagementPage] Using cached instances for ${cluster.name}`);
              if (!isNormalizedInstanceList(cachedInstances)) {
                globalCache.set('instances', normalized, clusterId);
              }
            } else {
              normalized = await fetchClusterInstances(clusterId);
            }
          } else {
            normalized = await fetchClusterInstances(clusterId);
          }
          instancesMap.set(clusterId, normalized.instances);
          totalsMap.set(clusterId, normalized.total);
        } catch (err) {
          console.error(`Failed to load instances for cluster ${cluster.name}:`, err);
          instancesMap.set(clusterId, []);
          totalsMap.set(clusterId, 0);
        }
      }
      setInstancesByCluster(instancesMap);
      setInstanceTotals(totalsMap);
      return null; // 成功返回 null
    } catch (err: unknown) {
      const errorMsg = (err as Error).message || "Failed to load data";
      setError(errorMsg);
      return errorMsg; // 返回错误消息
    } finally {
      if (shouldShowRefreshing) {
        setRefreshing(false);
      } else if (shouldShowLoading) {
        setLoading(false);
      }
    }
  }, []); // 没有任何依赖！

  // 初始加载 - 只执行一次
  useEffect(() => {
    let mounted = true;
    
    const init = async () => {
      const error = await loadDataCore({ skipCache: false, mode: "initial" });
      if (mounted && error) {
        toastError(error);
      }
    };
    
    init();
    
    return () => {
      mounted = false;
    };
  }, [loadDataCore, toastError]); // loadDataCore 永远不会变化
  
  // 手动刷新函数 - 带 toast 提示，清除缓存
  const loadData = useCallback(async () => {
    toastInfo("Refreshing instances...", {
      title: "Instances Refresh",
      durationMs: 1800,
      mergeKey: "instances-refresh",
    });
    globalCache.clearType("instances");
    const error = await loadDataCore({ skipCache: true, mode: "manual" }); // manual refresh mode
    if (error) {
      toastError(error);
    } else {
      success(SuccessMessages.DATA_REFRESHED);
    }
  }, [loadDataCore, toastError, toastInfo, success]);

  const autoRefreshInFlight = useRef(false);

  const autoRefresh = useCallback(async () => {
    if (loading || refreshing || autoRefreshInFlight.current) {
      return;
    }

    autoRefreshInFlight.current = true;
    const error = await loadDataCore({ skipCache: true, mode: "auto" });
    if (error) {
      console.warn("[InstancesManagementPage] Auto refresh failed:", error);
    }
    autoRefreshInFlight.current = false;
  }, [loading, refreshing, loadDataCore]);

  useEffect(() => {
    const intervalId = window.setInterval(() => {
      void autoRefresh();
    }, AUTO_REFRESH_INTERVAL_MS);

    return () => {
      window.clearInterval(intervalId);
    };
  }, [autoRefresh]);

  const handleScale = useCallback((updatedInstance: InstanceResponse) => {
    setInstancesByCluster((prev) => {
      const next = new Map(prev);
      for (const [clusterId, insts] of next) {
        const idx = insts.findIndex((i) => i.id === updatedInstance.id);
        if (idx !== -1) {
          const updated = [...insts];
          updated[idx] = updatedInstance;
          next.set(clusterId, updated);
          break;
        }
      }
      return next;
    });
  }, []);

  const handleModify = useCallback((instance: Instance) => {
    setModifyInstance(instance);
  }, []);

  const handleViewEntries = useCallback((instance: Instance) => {
    setEntriesInstance(instance);
  }, []);

  const handleViewDiagnostics = useCallback((instance: Instance) => {
    setDiagnosticsInstance(instance);
  }, []);

  const handleModifyConfirm = useCallback(async (
    clusterId: string,
    instanceId: string,
    data: UpdateInstanceRequest
  ) => {
    toastInfo("Applying instance update...", {
      title: "Update Instance",
      durationMs: 1800,
      mergeKey: `instance-update-${instanceId}`,
    });
    try {
      await updateInstance({ clusterId, instanceId }, data);
      success(SuccessMessages.INSTANCE_UPGRADED);
      await loadData();
    } catch (err: unknown) {
      const errorMsg = formatApiError(err) || InstanceErrors.UPDATE_FAILED;
      toastError(errorMsg);
      throw new Error(errorMsg);
    }
  }, [toastInfo, success, loadData, toastError]);

  const handleTerminate = useCallback(async (instance: Instance) => {
    if (
      !confirm(
        `Are you sure you want to terminate instance "${instance.name}"? This action cannot be undone.`
      )
    ) {
      return;
    }

    if (!instance.clusterId || !instance.id) {
      toastError("Instance ID or Cluster ID is missing");
      return;
    }

    try {
      toastInfo(`Terminating "${instance.name || "instance"}"...`, {
        title: "Terminate Instance",
        durationMs: 1800,
        mergeKey: `instance-terminate-${instance.id || instance.clusterId}`,
      });
      await deleteInstance({ clusterId: instance.clusterId, instanceId: instance.id });
      success(SuccessMessages.INSTANCE_DELETED);
      await loadData();
    } catch (err: unknown) {
      toastError(formatApiError(err) || InstanceErrors.DELETE_FAILED);
    }
  }, [success, toastError, loadData, toastInfo]);

  // Get filtered instances - memoized to avoid recalculation on every render
  const filteredInstances = useMemo((): Array<{ cluster: Cluster; instance: Instance }> => {
    const result: Array<{ cluster: Cluster; instance: Instance }> = [];

    clusters.forEach((cluster) => {
      const clusterId = cluster.id;
      if (!clusterId) {
        return;
      }
      if (selectedCluster !== "all" && clusterId !== selectedCluster) {
        return;
      }

      const instances = instancesByCluster.get(clusterId) || [];
      instances.forEach((instance) => {
        result.push({ cluster, instance });
      });
    });

    return result;
  }, [clusters, selectedCluster, instancesByCluster]);

  // Calculate total instances - memoized
  const totalInstances = useMemo(() => {
    if (instanceTotals.size > 0) {
      return Array.from(instanceTotals.values()).reduce((sum, total) => sum + total, 0);
    }
    return Array.from(instancesByCluster.values()).reduce(
      (sum, instances) => sum + instances.length,
      0
    );
  }, [instanceTotals, instancesByCluster]);

  return (
    <div className="p-6">
      {/* Header */}
      <PageHeader
        title="Artifact - Instances"
        description="Manage service instances across clusters"
        icon={Boxes}
        iconColor="text-green-400"
        actions={
          <Button
            variant="secondary"
            icon={RefreshCw}
            onClick={loadData}
            loading={refreshing}
            spinIcon={true}
          >
            Refresh
          </Button>
        }
      />

      {/* Enhanced Stats with gradient cards */}
      {!loading && clusters.length > 0 && (
        <div className={`grid grid-cols-1 gap-5 mb-8 ${
          clusters.length > 1 ? 'md:grid-cols-3' : 'md:grid-cols-2'
        }`}>
          <div className="relative group overflow-hidden bg-white border border-blue-100 rounded-lg p-6 hover:border-blue-200 hover:shadow-md transition-all duration-300">
            <div className="relative flex items-center justify-between">
              <div>
                <p className="text-sm font-semibold text-blue-700 uppercase tracking-wider mb-2">Total Instances</p>
                <p className="text-4xl font-bold text-slate-900">{totalInstances}</p>
              </div>
              <div className="p-4 bg-blue-50 rounded-lg border border-blue-100">
                <Package className="w-8 h-8 text-blue-600" />
              </div>
            </div>
          </div>
          
          <div className="relative group overflow-hidden bg-white border border-emerald-100 rounded-lg p-6 hover:border-emerald-200 hover:shadow-md transition-all duration-300">
            <div className="relative flex items-center justify-between">
              <div>
                <p className="text-sm font-semibold text-emerald-700 uppercase tracking-wider mb-2">Clusters</p>
                <p className="text-4xl font-bold text-slate-900">{clusters.length}</p>
              </div>
              <div className="p-4 bg-emerald-50 rounded-lg border border-emerald-100">
                <Server className="w-8 h-8 text-emerald-600" />
              </div>
            </div>
          </div>
          
          {/* Only show Filtered when there are multiple clusters */}
          {clusters.length > 1 && (
            <div className="relative group overflow-hidden bg-white border border-violet-100 rounded-lg p-6 hover:border-violet-200 hover:shadow-md transition-all duration-300">
              <div className="relative flex items-center justify-between">
                <div>
                  <p className="text-sm font-semibold text-violet-700 uppercase tracking-wider mb-2">Showing</p>
                  <p className="text-4xl font-bold text-slate-900">{filteredInstances.length}</p>
                </div>
                <div className="p-4 bg-violet-50 rounded-lg border border-violet-100">
                  <Boxes className="w-8 h-8 text-violet-600" />
                </div>
              </div>
            </div>
          )}
        </div>
      )}

      {/* Enhanced Filters */}
      {clusters.length > 1 && (
        <div className="mb-6 p-5 bg-white border border-slate-200 rounded-lg shadow-sm">
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-3">
              <div className="p-2 bg-gradient-to-br from-cyan-500/20 to-blue-500/20 rounded-lg border border-cyan-500/30">
                <Server className="w-5 h-5 text-cyan-400" />
              </div>
              <label className="text-sm font-semibold text-slate-700">
                Filter by Cluster:
              </label>
            </div>
            <DropdownSelect
              value={selectedCluster}
              onChange={(value) => setSelectedCluster(value)}
              options={[
                { value: "all", label: "All Clusters" },
                ...clusters
                  .filter((cluster): cluster is ClusterResponse & { id: string } => Boolean(cluster.id))
                  .map((cluster) => {
                    const instanceCount = instancesByCluster.get(cluster.id)?.length || 0;
                    return {
                      value: cluster.id,
                      label: `${cluster.name || 'Unknown'} (${instanceCount} instances)`,
                    };
                  }),
              ]}
            />
          </div>
        </div>
      )}

      {/* Content */}
      <div>
        {loading ? (
          <LoadingState message="Loading instances..." />
        ) : error ? (
          <ErrorState
            message={error}
            onRetry={loadData}
          />
        ) : filteredInstances.length === 0 ? (
          <EmptyState
            icon={Package}
            title="No instances found"
            description="Launch your first service instance from Artifact Registries"
          />
        ) : (
          <div className="space-y-6">
            {/* Group by cluster if showing all */}
            {selectedCluster === "all" ? (
              clusters.map((cluster, index) => {
                const clusterId = cluster.id;
                if (!clusterId) return null;
                const instances = instancesByCluster.get(clusterId) || [];
                if (instances.length === 0) return null;

                return (
                  <div key={clusterId || `cluster-${index}`} className="mb-8">
                    <div className="flex items-center gap-3 mb-5">
                      <div className="p-2.5 bg-gradient-to-br from-emerald-500/20 to-green-500/20 rounded-lg border border-emerald-500/30 shadow-lg shadow-emerald-500/10">
                        <Server className="w-5 h-5 text-emerald-400" />
                      </div>
                      <div>
                        <h2 className="text-xl font-bold text-slate-900">
                          {cluster.name || "Unnamed Cluster"}
                        </h2>
                        <p className="text-sm text-slate-500 mt-0.5">
                          {instances.length} {instances.length === 1 ? 'instance' : 'instances'} running
                        </p>
                      </div>
                    </div>
                    <div className="flex flex-col gap-2">
                      {instances.map((instance) => (
                        <InstanceCard
                          key={instance.id}
                          instance={instance}
                          onModify={handleModify}
                          onTerminate={handleTerminate}

                          onScale={handleScale}
                          onViewEntries={handleViewEntries}
                          onViewDiagnostics={handleViewDiagnostics}
                        />
                      ))}
                    </div>
                  </div>
                );
              })
            ) : (
              <div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
                {filteredInstances.map(({ instance }) => (
                <InstanceCard
                  key={instance.id}
                  instance={instance}
                  onModify={handleModify}
                  onTerminate={handleTerminate}

                  onViewEntries={handleViewEntries}
                  onViewDiagnostics={handleViewDiagnostics}
                />
                ))}
              </div>
            )}
          </div>
        )}
      </div>

      {/* Modals */}
      {modifyInstance && (
        <ModifyModal
          instance={modifyInstance}
          onClose={() => setModifyInstance(null)}
          onConfirm={handleModifyConfirm}
        />
      )}

      {entriesInstance && (
        <EntriesModal
          instance={entriesInstance}
          onClose={() => setEntriesInstance(null)}
        />
      )}

      {diagnosticsInstance && (
        <DiagnosticsModal
          instance={diagnosticsInstance}
          onClose={() => setDiagnosticsInstance(null)}
        />
      )}
    </div>
  );
};

export default InstancesManagementPage;

async function fetchClusterInstances(clusterId: string): Promise<NormalizedInstanceList> {
  const response = await listInstances({ clusterId });
  const normalized = normalizeInstanceList(response);
  globalCache.set('instances', normalized, clusterId);
  return normalized;
}

function normalizeInstanceList(raw: unknown): NormalizedInstanceList {
  if (Array.isArray(raw)) {
    return {
      instances: raw as InstanceResponse[],
      total: raw.length,
    };
  }

  if (raw && typeof raw === "object") {
    const payload = raw as InstanceListPayloadWithMeta;
    const direct = extractInstancesFromPayload(payload);
    if (direct) {
      return direct;
    }

    if (payload.data !== undefined) {
      const nested = normalizeInstanceList(payload.data);
      return {
        instances: nested.instances,
        total: pickTotalValue(payload.total, payload.meta, nested.total),
      };
    }
  }

  return { instances: [], total: 0 };
}

function extractInstancesFromPayload(payload: InstanceListPayloadWithMeta): NormalizedInstanceList | null {
  if (Array.isArray(payload.instances)) {
    const instances = payload.instances as InstanceResponse[];
    return {
      instances,
      total: pickTotalValue(payload.total, payload.meta, instances.length),
    };
  }

  if (Array.isArray(payload.items)) {
    const instances = payload.items as InstanceResponse[];
    return {
      instances,
      total: pickTotalValue(payload.total, payload.meta, instances.length),
    };
  }

  if (payload.data && typeof payload.data === "object") {
    return extractInstancesFromPayload(payload.data as InstanceListPayloadWithMeta);
  }

  return null;
}

function pickTotalValue(totalValue: unknown, metaValue: unknown, fallback: number): number {
  if (typeof totalValue === "number" && Number.isFinite(totalValue)) {
    return totalValue;
  }

  const metaTotal = getMetaTotal(metaValue);
  if (typeof metaTotal === "number") {
    return metaTotal;
  }

  return fallback;
}

function getMetaTotal(metaValue: unknown): number | undefined {
  if (metaValue && typeof metaValue === "object") {
    const meta = metaValue as Record<string, unknown>;
    if (typeof meta.total === "number") {
      return meta.total;
    }
    if (typeof meta.count === "number") {
      return meta.count;
    }
  }

  return undefined;
}

function isNormalizedInstanceList(data: unknown): data is NormalizedInstanceList {
  return (
    !!data &&
    typeof data === "object" &&
    Array.isArray((data as NormalizedInstanceList).instances) &&
    typeof (data as NormalizedInstanceList).total === "number"
  );
}

type InstanceListPayloadWithMeta = {
  instances?: unknown;
  items?: unknown;
  data?: unknown;
  total?: unknown;
  meta?: unknown;
};

interface NormalizedInstanceList {
  instances: InstanceResponse[];
  total: number;
}
