/**
 * Entries Modal Component
 * 显示实例的入口信息（Services 和 Ingresses）
 */
import React, { useState, useEffect } from "react";
import { X, Globe, Network, ExternalLink, Copy, CheckCircle, Info } from "lucide-react";
import { listInstanceEntries } from "@/api";
import type { InstanceEntry, InstanceResponse } from "@/api";
import { useToast } from "@/shared";

interface ServiceEntry {
  name?: string;
  namespace?: string;
  type?: string;
  cluster_ip?: string;
  external_ips?: string[];
  ports?: Array<{
    name?: string;
    protocol?: string;
    port?: number | string;
    target_port?: number | string;
    node_port?: number;
  }>;
  loadBalancer?: {
    ingress?: Array<{
      ip?: string;
      hostname?: string;
    }>;
  };
}

interface IngressEntry {
  name?: string;
  namespace?: string;
  class_name?: string;
  rules?: Array<{
    host?: string;
    paths?: Array<{
      path?: string;
      path_type?: string;
      backend?: {
        service?: {
          name?: string;
          port?: number | string;
        };
      };
    }>;
  }>;
  tls?: Array<{
    hosts?: string[];
    secret_name?: string;
  }>;
}

type EntrySource = 'kubernetes' | 'manifest' | 'notes' | 'none';

interface InstanceEntries {
  services: ServiceEntry[];
  ingresses: IngressEntry[];
  source: EntrySource;
  notes?: string;
}

const NESTED_ENTRY_KEYS = ["entries", "data", "result", "results", "payload", "services", "ingresses"];

function isPlainObject(value: unknown): value is Record<string, unknown> {
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}

function collectEntryContainers(value: unknown, seen = new Set<unknown>()): Record<string, unknown>[] {
  if (!isPlainObject(value) || seen.has(value)) {
    return [];
  }
  seen.add(value);
  const containers: Record<string, unknown>[] = [value];
  for (const key of NESTED_ENTRY_KEYS) {
    const nested = (value as Record<string, unknown>)[key];
    if (isPlainObject(nested)) {
      containers.push(...collectEntryContainers(nested, seen));
    }
  }
  return containers;
}

function asEntryArray(value: unknown, seen = new Set<unknown>()): InstanceEntry[] | undefined {
  if (Array.isArray(value)) {
    return value as InstanceEntry[];
  }
  if (isPlainObject(value)) {
    if (seen.has(value)) {
      return undefined;
    }
    seen.add(value);
    return (
      asEntryArray(value.entries, seen) ||
      asEntryArray(value.items, seen) ||
      asEntryArray(value.data, seen)
    );
  }
  return undefined;
}

const ENTRY_SOURCES: EntrySource[] = ["kubernetes", "manifest", "notes", "none"];

async function getInstanceEntries(clusterId: string, instanceId: string): Promise<InstanceEntries> {
  const raw = (await listInstanceEntries({ clusterId, instanceId })) as unknown;
  return buildInstanceEntries(raw);
}

function buildInstanceEntries(raw: unknown): InstanceEntries {
  const baseState: InstanceEntries = {
    services: [],
    ingresses: [],
    source: "none",
  };

  if (raw == null) {
    return baseState;
  }

  let entriesPayload: InstanceEntry[] | undefined = Array.isArray(raw) ? (raw as InstanceEntry[]) : undefined;
  let source: EntrySource = "none";
  let notes: string | undefined;
  let servicesFromResponse: InstanceEntry[] | undefined;
  let ingressesFromResponse: InstanceEntry[] | undefined;

  const containers = collectEntryContainers(raw);
  for (const container of containers) {
    entriesPayload ||= asEntryArray(container.entries);
    entriesPayload ||= asEntryArray(container.items);
    entriesPayload ||= asEntryArray(container.data);
    servicesFromResponse ||= asEntryArray(container.services);
    ingressesFromResponse ||= asEntryArray(container.ingresses);
    if (!notes && typeof container.notes === "string") {
      notes = container.notes;
    }
    if (typeof container.source === "string") {
      const normalized = normalizeSource(container.source);
      if (normalized) {
        source = normalized;
      }
    }
  }

  const entries = entriesPayload ?? [];
  const splitResult = entries.length ? splitEntries(entries) : { services: [], ingresses: [] };
  const explicitServices = servicesFromResponse?.map(mapServiceEntry) ?? [];
  const explicitIngresses = ingressesFromResponse?.map(mapIngressEntry) ?? [];
  const services = explicitServices.length ? explicitServices : splitResult.services;
  const ingresses = explicitIngresses.length ? explicitIngresses : splitResult.ingresses;
  const resolvedSource: EntrySource =
    services.length || ingresses.length
      ? source === "none"
        ? "kubernetes"
        : source
      : source;

  return {
    services,
    ingresses,
    source: resolvedSource,
    notes,
  };
}

function normalizeSource(source: string): EntrySource | null {
  if (ENTRY_SOURCES.includes(source as EntrySource)) {
    return source as EntrySource;
  }
  return null;
}

function splitEntries(entries: InstanceEntry[]): {
  services: ServiceEntry[];
  ingresses: IngressEntry[];
} {
  if (!entries.length) {
    return { services: [], ingresses: [] };
  }
  const services: ServiceEntry[] = [];
  const ingresses: IngressEntry[] = [];

  entries.forEach((entry) => {
    const kind = entry.kind?.toLowerCase();
    const looksLikeIngress =
      kind === "ingress" ||
      (!!entry.hosts && entry.hosts.length > 0) ||
      (!!entry.tls && entry.tls.length > 0);
    const looksLikeService =
      kind === "service" ||
      (!!entry.ports && entry.ports.length > 0) ||
      !!entry.clusterIP ||
      !!entry.type;

    if (kind === "ingress" || (looksLikeIngress && !looksLikeService)) {
      ingresses.push(mapIngressEntry(entry));
    } else {
      services.push(mapServiceEntry(entry));
    }
  });

  return { services, ingresses };
}

function mapServiceEntry(entry: InstanceEntry): ServiceEntry {
  return {
    name: entry.name,
    namespace: entry.namespace,
    type: entry.type,
    cluster_ip: entry.clusterIP,
    external_ips: entry.externalIPs,
    ports: entry.ports?.map((port) => ({
      name: port.name,
      protocol: port.protocol,
      port: port.port ?? port.targetPort,
      target_port: port.targetPort ?? port.port,
      node_port: port.nodePort,
    })),
    loadBalancer: mapLoadBalancer(entry.loadBalancerIngress),
  };
}

function mapIngressEntry(entry: InstanceEntry): IngressEntry {
  return {
    name: entry.name,
    namespace: entry.namespace,
    class_name: entry.type,
    rules: entry.hosts?.map((host) => ({
      host: host.host,
      paths: host.paths?.map((path) => ({
        path: path.path,
        backend: {
          service: {
            name: path.serviceName,
            port: normalizePort(path.servicePort),
          },
        },
      })),
    })),
    tls: entry.tls?.map((tls) => ({
      hosts: tls.hosts,
      secret_name: tls.secretName,
    })),
  };
}

function mapLoadBalancer(values?: string[]) {
  if (!values || !values.length) {
    return undefined;
  }
  return {
    ingress: values.map((value) => {
      if (!value) {
        return {};
      }
      const hasAlpha = /[a-zA-Z]/.test(value);
      if (hasAlpha) {
        return { hostname: value };
      }
      return { ip: value };
    }),
  };
}

function normalizePort(port?: string | number | null): number | string | undefined {
  if (port == null) {
    return undefined;
  }
  if (typeof port === "number") {
    return port;
  }
  const parsed = Number(port);
  if (!Number.isNaN(parsed)) {
    return parsed;
  }
  return port;
}

interface EntriesModalProps {
  instance: InstanceResponse;
  onClose: () => void;
}

export const EntriesModal: React.FC<EntriesModalProps> = ({ instance, onClose }) => {
  const { success } = useToast();
  const [entries, setEntries] = useState<InstanceEntries | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [copiedText, setCopiedText] = useState<string | null>(null);

  useEffect(() => {
    const loadEntries = async () => {
      if (!instance.clusterId || !instance.id) {
        setError("Instance identifier is missing");
        setLoading(false);
        return;
      }
      try {
        setLoading(true);
        const data = await getInstanceEntries(instance.clusterId, instance.id);
        setEntries(data);
      } catch (err: unknown) {
        setError((err as Error).message || "Failed to load entries");
      } finally {
        setLoading(false);
      }
    };

    loadEntries();
  }, [instance.clusterId, instance.id]);

  const copyToClipboard = (text: string, label: string) => {
    navigator.clipboard.writeText(text);
    setCopiedText(text);
    success(`Copied ${label} to clipboard`);
    setTimeout(() => setCopiedText(null), 2000);
  };

  const getSourceBadge = (source?: string) => {
    const badges = {
      kubernetes: { color: "bg-green-600/20 text-green-400 border-green-500/30", label: "Live from Kubernetes" },
      manifest: { color: "bg-blue-600/20 text-blue-400 border-blue-500/30", label: "From Helm Manifest" },
      notes: { color: "bg-yellow-600/20 text-yellow-400 border-yellow-500/30", label: "From Helm Notes" },
      none: { color: "bg-slate-200/20 text-slate-500 border-gray-500/30", label: "No Data Available" },
    };

    const badge = badges[source as keyof typeof badges] || badges.none;

    return (
      <span className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium border ${badge.color}`}>
        <Info className="w-3 h-3" />
        {badge.label}
      </span>
    );
  };

  const renderService = (service: ServiceEntry, index: number) => (
    <div key={service.name || `service-${index}`} className="bg-slate-50 border border-slate-200 rounded-lg p-4 space-y-3">
      <div className="flex items-start justify-between">
        <div>
          <h4 className="text-sm font-semibold text-slate-900">{service.name || `Service ${index + 1}`}</h4>
          <p className="text-xs text-slate-500 mt-1">Type: {service.type || 'Unknown'}</p>
        </div>
        <span className="px-2 py-1 text-xs font-medium bg-blue-600/20 text-blue-400 border border-blue-500/30 rounded">
          {service.type || 'Unknown'}
        </span>
      </div>

      <div className="space-y-2">
        {/* Cluster IP */}
        {service.cluster_ip && (
          <div className="flex items-center justify-between bg-slate-50 rounded p-2">
            <span className="text-xs text-slate-500">Cluster IP:</span>
            <div className="flex items-center gap-2">
              <span className="text-sm font-mono text-slate-900">{service.cluster_ip}</span>
              <button
                onClick={() => copyToClipboard(service.cluster_ip!, "Cluster IP")}
                className="p-1 hover:bg-slate-100 rounded transition"
              >
                {copiedText === service.cluster_ip ? (
                  <CheckCircle className="w-3 h-3 text-green-400" />
                ) : (
                  <Copy className="w-3 h-3 text-slate-500" />
                )}
              </button>
            </div>
          </div>
        )}

        {/* Ports */}
        {service.ports && service.ports.length > 0 && service.ports.map((port, idx) => (
          <div key={idx} className="flex items-center justify-between bg-slate-50 rounded p-2">
            <span className="text-xs text-slate-500">{port.name || `Port ${idx + 1}`}:</span>
            <div className="flex items-center gap-2">
              <span className="text-sm font-mono text-slate-900">
                {port.port} → {port.target_port} {port.protocol || 'TCP'}
                {port.node_port && ` (NodePort: ${port.node_port})`}
              </span>
            </div>
          </div>
        ))}

        {/* LoadBalancer Status */}
        {service.loadBalancer?.ingress && service.loadBalancer.ingress.length > 0 && (
          <div className="mt-2 p-2 bg-green-600/10 border border-green-500/30 rounded">
            <p className="text-xs text-green-400 mb-2 font-medium">LoadBalancer Entries:</p>
            {service.loadBalancer.ingress.map((ing, idx) => (
              <div key={idx} className="flex items-center justify-between mb-1">
                <span className="text-sm font-mono text-slate-900">
                  {ing.ip || ing.hostname}
                </span>
                <div className="flex items-center gap-2">
                  {ing.ip && (
                    <>
                      <a
                        href={`http://${ing.ip}:${service.ports?.[0]?.port || 80}`}
                        target="_blank"
                        rel="noopener noreferrer"
                        className="p-1 hover:bg-slate-100 rounded transition"
                        title="Open in browser"
                      >
                        <ExternalLink className="w-3 h-3 text-blue-400" />
                      </a>
                      <button
                        onClick={() => copyToClipboard(ing.ip!, "IP")}
                        className="p-1 hover:bg-slate-100 rounded transition"
                      >
                        {copiedText === ing.ip ? (
                          <CheckCircle className="w-3 h-3 text-green-400" />
                        ) : (
                          <Copy className="w-3 h-3 text-slate-500" />
                        )}
                      </button>
                    </>
                  )}
                </div>
              </div>
            ))}
          </div>
        )}
      </div>
    </div>
  );

  const renderIngress = (ingress: IngressEntry, index: number) => (
    <div key={ingress.name || `ingress-${index}`} className="bg-slate-50 border border-slate-200 rounded-lg p-4 space-y-3">
      <div className="flex items-start justify-between">
        <div>
          <h4 className="text-sm font-semibold text-slate-900">{ingress.name || `Ingress ${index + 1}`}</h4>
          {ingress.class_name && (
            <p className="text-xs text-slate-500 mt-1">Class: {ingress.class_name}</p>
          )}
        </div>
        <Globe className="w-5 h-5 text-purple-400" />
      </div>

      <div className="space-y-2">
        {ingress.rules?.map((rule, ruleIdx) => (
          <div key={ruleIdx} className="bg-slate-50 rounded p-3 space-y-2">
            {(() => {
              const host = rule.host;
              if (!host) return null;
              return (
              <div className="flex items-center justify-between mb-2">
                <span className="text-sm font-medium text-slate-900">{host}</span>
                <div className="flex items-center gap-2">
                  <a
                    href={`https://${host}`}
                    target="_blank"
                    rel="noopener noreferrer"
                    className="p-1 hover:bg-slate-100 rounded transition"
                  >
                    <ExternalLink className="w-3 h-3 text-blue-400" />
                  </a>
                  <button
                    onClick={() => copyToClipboard(host, "Host")}
                    className="p-1 hover:bg-slate-100 rounded transition"
                  >
                    {copiedText === host ? (
                      <CheckCircle className="w-3 h-3 text-green-400" />
                    ) : (
                      <Copy className="w-3 h-3 text-slate-500" />
                    )}
                  </button>
                </div>
              </div>
              );
            })()}
            {rule.paths?.map((path, pathIdx) => {
              const serviceName = path.backend?.service?.name || "service";
              const servicePort = path.backend?.service?.port ?? "-";
              return (
                <div key={pathIdx} className="text-xs text-slate-500 ml-4">
                  • {path.path || '/'} → {serviceName}:{servicePort}
                </div>
              );
            })}
          </div>
        ))}

        {ingress.tls && ingress.tls.length > 0 && (
          <div className="mt-2 p-2 bg-blue-600/10 border border-blue-500/30 rounded">
            <p className="text-xs text-blue-400 font-medium">🔒 TLS Enabled</p>
          </div>
        )}
      </div>
    </div>
  );

  return (
    <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 p-4">
      <div className="bg-white border border-slate-200 rounded-lg max-w-4xl w-full max-h-[90vh] flex flex-col">
        {/* Header */}
        <div className="flex items-center justify-between p-6 border-b border-slate-200">
          <div>
            <h2 className="text-xl font-semibold text-slate-900">Instance Entries</h2>
            <p className="text-sm text-slate-500 mt-1">
              {instance.name} ({instance.namespace})
            </p>
          </div>
          <button
            onClick={onClose}
            className="p-2 hover:bg-white rounded-lg transition"
          >
            <X className="w-5 h-5 text-slate-500" />
          </button>
        </div>

        {/* Content */}
        <div className="flex-1 overflow-y-auto p-6">
          {loading ? (
            <div className="flex items-center justify-center py-12">
              <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
              <span className="ml-3 text-slate-500">Loading entries...</span>
            </div>
          ) : error ? (
            <div className="text-center py-12">
              <p className="text-red-400">{error}</p>
              <button
                onClick={onClose}
                className="mt-4 px-4 py-2 bg-white text-slate-900 rounded-lg hover:bg-slate-100 transition"
              >
                Close
              </button>
            </div>
          ) : entries ? (
            <div className="space-y-6">
              {/* Source Badge */}
              <div className="flex items-center justify-between">
                <h3 className="text-sm font-medium text-slate-500">Data Source:</h3>
                {getSourceBadge(entries.source)}
              </div>

              {/* Services */}
              {entries.services && entries.services.length > 0 && (
                <div>
                  <div className="flex items-center gap-2 mb-3">
                    <Network className="w-5 h-5 text-blue-400" />
                    <h3 className="text-lg font-semibold text-slate-900">
                      Services ({entries.services.length})
                    </h3>
                  </div>
                  <div className="space-y-3">
                    {entries.services.map(renderService)}
                  </div>
                </div>
              )}

              {/* Ingresses */}
              {entries.ingresses && entries.ingresses.length > 0 && (
                <div>
                  <div className="flex items-center gap-2 mb-3">
                    <Globe className="w-5 h-5 text-purple-400" />
                    <h3 className="text-lg font-semibold text-slate-900">
                      Ingresses ({entries.ingresses.length})
                    </h3>
                  </div>
                  <div className="space-y-3">
                    {entries.ingresses.map(renderIngress)}
                  </div>
                </div>
              )}

              {/* Helm Notes (as fallback) */}
              {entries.notes && entries.source === "notes" && (
                <div>
                  <h3 className="text-lg font-semibold text-slate-900 mb-3">Helm Notes</h3>
                  <div className="bg-slate-50 border border-slate-200 rounded-lg p-4">
                    <pre className="text-xs text-slate-700 whitespace-pre-wrap font-mono">
                      {entries.notes}
                    </pre>
                  </div>
                </div>
              )}

              {/* Empty State */}
              {(!entries.services || entries.services.length === 0) && 
               (!entries.ingresses || entries.ingresses.length === 0) && 
               !entries.notes && (
                <div className="text-center py-12">
                  <Network className="w-12 h-12 text-gray-600 mx-auto mb-4" />
                  <p className="text-slate-500">No entries found for this instance</p>
                  <p className="text-xs text-slate-500 mt-2">Data source: {entries.source || 'unknown'}</p>
                </div>
              )}
            </div>
          ) : null}
        </div>

        {/* Footer */}
        <div className="p-6 border-t border-slate-200 flex justify-end">
          <button
            onClick={onClose}
            className="px-4 py-2 bg-white text-slate-900 rounded-lg hover:bg-slate-100 transition"
          >
            Close
          </button>
        </div>
      </div>
    </div>
  );
};
