"use client";

import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useSettings } from "@/app/lib/settings";
import { useAppStore } from "@/app/lib/store";
import {
  ApiError,
  fetchClients,
  fetchRows,
  insertRow,
  deleteRow,
  pingServer,
  listS3Objects,
  getS3ObjectUrl,
  deleteS3Object,
  createS3Folder,
  getS3UploadUrl,
  type RowValues,
  type S3Object,
  type S3Creds,
} from "@/app/lib/api";
import { Badge } from "./ui/badge";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "./ui/dialog";
import {
  BookOpen,
  ChevronRight,
  Download,
  Eye,
  File,
  FileText,
  Folder,
  FolderPlus,
  Home,
  Image,
  Loader2,
  Plus,
  RefreshCw,
  Server,
  Trash2,
  Upload,
  Wifi,
  WifiOff,
  Zap,
} from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/app/lib/utils";
import { z } from "zod";

type Provider = "aws-s3" | "minio" | "hetzner" | "cloudflare-r2";

type S3Profile = {
  id?: string;
  name: string;
  provider: Provider;
  endpoint: string;
  region: string;
  bucket: string;
  access_key_id: string;
  secret_key: string;
  created_at?: string;
};

type ConnectorStatus = {
  name: string;
  ok: boolean;
  latencyMs: number;
  version?: string;
  lastChecked: number;
};

const LOGGING_CLIENT = "athena_logging";
const PROFILES_TABLE = "storage_profiles";

const PROVIDER_PRESETS: Record<
  Provider,
  { endpointHint: string; regionHint: string }
> = {
  "aws-s3": {
    endpointHint: "https://s3.amazonaws.com",
    regionHint: "eu-central-1",
  },
  minio: { endpointHint: "https://minio.example.com", regionHint: "us-east-1" },
  hetzner: {
    endpointHint: "https://fsn1.your-objectstorage.com",
    regionHint: "eu-central",
  },
  "cloudflare-r2": {
    endpointHint: "https://<accountid>.r2.cloudflarestorage.com",
    regionHint: "auto",
  },
};

const profileSchema = z.object({
  name: z.string().trim().min(1, "Profile name is required"),
  endpoint: z.string().trim().min(1, "Endpoint is required"),
  bucket: z.string().trim().min(1, "Bucket is required"),
  region: z.string().trim().min(1, "Region is required"),
});

function formatBytes(bytes: number): string {
  if (bytes === 0) return "0 B";
  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB", "TB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
}

function fileIcon(key: string) {
  const ext = key.split(".").pop()?.toLowerCase() ?? "";
  if (["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "ico"].includes(ext))
    return Image;
  if (
    [
      "md",
      "txt",
      "csv",
      "log",
      "json",
      "yaml",
      "yml",
      "xml",
      "html",
      "css",
      "js",
      "ts",
    ].includes(ext)
  )
    return FileText;
  return File;
}

function mimeFromKey(key: string): string {
  const ext = key.split(".").pop()?.toLowerCase() ?? "";
  const map: Record<string, string> = {
    jpg: "image/jpeg",
    jpeg: "image/jpeg",
    png: "image/png",
    gif: "image/gif",
    webp: "image/webp",
    svg: "image/svg+xml",
    pdf: "application/pdf",
    json: "application/json",
    xml: "application/xml",
    html: "text/html",
    css: "text/css",
    js: "text/javascript",
    ts: "text/typescript",
    md: "text/markdown",
    txt: "text/plain",
    csv: "text/csv",
    zip: "application/zip",
    gz: "application/gzip",
    tar: "application/x-tar",
  };
  return map[ext] ?? "application/octet-stream";
}

export default function StoragePage() {
  const { baseUrl, apiKey } = useSettings();
  const { selectedClient } = useAppStore();
  const ctx = useMemo(() => ({ baseUrl, apiKey }), [baseUrl, apiKey]);

  // ── S3 Profiles ──
  const [profiles, setProfiles] = useState<S3Profile[]>([]);
  const [profilesLoading, setProfilesLoading] = useState(true);
  const [provider, setProvider] = useState<Provider>("aws-s3");
  const [name, setName] = useState("");
  const [endpoint, setEndpoint] = useState(
    PROVIDER_PRESETS["aws-s3"].endpointHint,
  );
  const [region, setRegion] = useState(PROVIDER_PRESETS["aws-s3"].regionHint);
  const [bucket, setBucket] = useState("");
  const [accessKeyId, setAccessKeyId] = useState("");
  const [secretKey, setSecretKey] = useState("");
  const [saving, setSaving] = useState(false);
  const [deleteTarget, setDeleteTarget] = useState<S3Profile | null>(null);
  const [deleting, setDeleting] = useState(false);

  // ── S3 Browser ──
  const [activeProfile, setActiveProfile] = useState<S3Profile | null>(null);
  const [currentPrefix, setCurrentPrefix] = useState("");
  const [objects, setObjects] = useState<S3Object[]>([]);
  const [folders, setFolders] = useState<string[]>([]);
  const [browseLoading, setBrowseLoading] = useState(false);
  const [browseError, setBrowseError] = useState<string | null>(null);
  const [deleteObjectTarget, setDeleteObjectTarget] = useState<S3Object | null>(
    null,
  );
  const [deletingObject, setDeletingObject] = useState(false);
  const [newFolderOpen, setNewFolderOpen] = useState(false);
  const [newFolderName, setNewFolderName] = useState("");
  const [creatingFolder, setCreatingFolder] = useState(false);
  const [uploading, setUploading] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  // ── Connectors ──
  const [clients, setClients] = useState<string[]>([]);
  const [connectorStatuses, setConnectorStatuses] = useState<
    Map<string, ConnectorStatus>
  >(new Map());
  const [connectorsLoading, setConnectorsLoading] = useState(true);
  const [autoRefresh, setAutoRefresh] = useState(true);

  const profileCreds = useCallback(
    (p: S3Profile): S3Creds => ({
      endpoint: p.endpoint,
      region: p.region,
      bucket: p.bucket,
      access_key_id: p.access_key_id,
      secret_key: p.secret_key,
    }),
    [],
  );

  // ── Load profiles ──
  const loadProfiles = useCallback(async () => {
    setProfilesLoading(true);
    try {
      const rows = await fetchRows(
        ctx,
        PROFILES_TABLE,
        ["*"],
        LOGGING_CLIENT,
        undefined,
        true,
      );
      const mapped: S3Profile[] = rows.map((r) => ({
        id: String(r.id ?? r.storage_profiles_id ?? ""),
        name: String(r.name ?? ""),
        provider: String(r.provider ?? "aws-s3") as Provider,
        endpoint: String(r.endpoint ?? ""),
        region: String(r.region ?? ""),
        bucket: String(r.bucket ?? ""),
        access_key_id: String(r.access_key_id ?? ""),
        secret_key: String(r.secret_key ?? ""),
        created_at: r.created_at ? String(r.created_at) : undefined,
      }));
      setProfiles(mapped);
    } catch {
      setProfiles([]);
    } finally {
      setProfilesLoading(false);
    }
  }, [ctx]);

  useEffect(() => {
    void loadProfiles();
  }, [loadProfiles]);

  // ── Browse S3 ──
  const browsePrefix = useCallback(
    async (profile: S3Profile, prefix: string) => {
      setBrowseLoading(true);
      setBrowseError(null);
      try {
        const resp = await listS3Objects(ctx, profileCreds(profile), prefix);
        setObjects(resp.objects.filter((o) => !o.is_folder));
        setFolders(resp.common_prefixes);
        setCurrentPrefix(prefix);
      } catch (err) {
        const msg =
          err instanceof ApiError ? err.message : "Failed to browse bucket";
        setBrowseError(msg);
        toast.error(msg);
      } finally {
        setBrowseLoading(false);
      }
    },
    [ctx, profileCreds],
  );

  const handleSelectProfile = useCallback(
    (p: S3Profile) => {
      setActiveProfile(p);
      setCurrentPrefix("");
      void browsePrefix(p, "");
    },
    [browsePrefix],
  );

  const navigateToFolder = useCallback(
    (prefix: string) => {
      if (!activeProfile) return;
      void browsePrefix(activeProfile, prefix);
    },
    [activeProfile, browsePrefix],
  );

  const navigateUp = useCallback(() => {
    if (!currentPrefix) return;
    const parts = currentPrefix.replace(/\/$/, "").split("/");
    parts.pop();
    const parent = parts.length > 0 ? parts.join("/") + "/" : "";
    navigateToFolder(parent);
  }, [currentPrefix, navigateToFolder]);

  const breadcrumbs = useMemo(() => {
    if (!currentPrefix) return [];
    const parts = currentPrefix.replace(/\/$/, "").split("/");
    return parts.map((part, i) => ({
      label: part,
      prefix: parts.slice(0, i + 1).join("/") + "/",
    }));
  }, [currentPrefix]);

  // ── Download ──
  const handleDownload = useCallback(
    async (obj: S3Object) => {
      if (!activeProfile) return;
      try {
        const url = await getS3ObjectUrl(
          ctx,
          profileCreds(activeProfile),
          obj.key,
        );
        window.open(url, "_blank");
      } catch (err) {
        toast.error(err instanceof ApiError ? err.message : "Download failed");
      }
    },
    [activeProfile, ctx, profileCreds],
  );

  // ── Preview ──
  const handlePreview = useCallback(
    async (obj: S3Object) => {
      if (!activeProfile) return;
      try {
        const url = await getS3ObjectUrl(
          ctx,
          profileCreds(activeProfile),
          obj.key,
        );
        window.open(url, "_blank");
      } catch (err) {
        toast.error(err instanceof ApiError ? err.message : "Preview failed");
      }
    },
    [activeProfile, ctx, profileCreds],
  );

  // ── Delete object ──
  const handleDeleteObject = useCallback(async () => {
    if (!activeProfile || !deleteObjectTarget) return;
    setDeletingObject(true);
    try {
      await deleteS3Object(
        ctx,
        profileCreds(activeProfile),
        deleteObjectTarget.key,
      );
      toast.success(`Deleted ${deleteObjectTarget.key.split("/").pop()}`);
      setDeleteObjectTarget(null);
      void browsePrefix(activeProfile, currentPrefix);
    } catch (err) {
      toast.error(err instanceof ApiError ? err.message : "Delete failed");
    } finally {
      setDeletingObject(false);
    }
  }, [
    activeProfile,
    deleteObjectTarget,
    ctx,
    profileCreds,
    browsePrefix,
    currentPrefix,
  ]);

  // ── Create folder ──
  const handleCreateFolder = useCallback(async () => {
    if (!activeProfile || !newFolderName.trim()) return;
    setCreatingFolder(true);
    try {
      const fullPrefix = currentPrefix + newFolderName.trim();
      await createS3Folder(ctx, profileCreds(activeProfile), fullPrefix);
      toast.success("Folder created");
      setNewFolderOpen(false);
      setNewFolderName("");
      void browsePrefix(activeProfile, currentPrefix);
    } catch (err) {
      toast.error(
        err instanceof ApiError ? err.message : "Create folder failed",
      );
    } finally {
      setCreatingFolder(false);
    }
  }, [
    activeProfile,
    newFolderName,
    currentPrefix,
    ctx,
    profileCreds,
    browsePrefix,
  ]);

  // ── Upload ──
  const handleUpload = useCallback(
    async (e: React.ChangeEvent<HTMLInputElement>) => {
      const file = e.target.files?.[0];
      if (!file || !activeProfile) return;
      e.target.value = "";

      setUploading(true);
      try {
        const key = currentPrefix + file.name;
        const contentType = file.type || mimeFromKey(file.name);
        const { url } = await getS3UploadUrl(
          ctx,
          profileCreds(activeProfile),
          key,
          contentType,
        );
        if (!url) throw new Error("No upload URL returned");

        const resp = await fetch(url, {
          method: "PUT",
          body: file,
          headers: { "Content-Type": contentType },
        });
        if (!resp.ok) throw new Error(`Upload failed: ${resp.status}`);

        toast.success(`Uploaded ${file.name}`);
        void browsePrefix(activeProfile, currentPrefix);
      } catch (err) {
        toast.error(err instanceof Error ? err.message : "Upload failed");
      } finally {
        setUploading(false);
      }
    },
    [activeProfile, currentPrefix, ctx, profileCreds, browsePrefix],
  );

  // ── Connectors ──
  const loadConnectors = useCallback(async () => {
    try {
      const clientList = await fetchClients(ctx);
      setClients(clientList);
    } catch {
      /* ignore */
    } finally {
      setConnectorsLoading(false);
    }
  }, [ctx]);

  const healthCheckConnectors = useCallback(async () => {
    if (clients.length === 0) return;
    const result = await pingServer(baseUrl);
    const next = new Map<string, ConnectorStatus>();
    for (const c of clients) {
      next.set(c, {
        name: c,
        ok: result.ok,
        latencyMs: result.latencyMs,
        version: result.version,
        lastChecked: Date.now(),
      });
    }
    setConnectorStatuses(next);
  }, [clients, baseUrl]);

  useEffect(() => {
    void loadConnectors();
  }, [loadConnectors]);
  useEffect(() => {
    if (clients.length > 0) void healthCheckConnectors();
  }, [clients, healthCheckConnectors]);
  useEffect(() => {
    if (!autoRefresh) return;
    const timer = setInterval(() => {
      void loadConnectors();
      void healthCheckConnectors();
    }, 10000);
    return () => clearInterval(timer);
  }, [autoRefresh, loadConnectors, healthCheckConnectors]);

  // ── Profile form ──
  const setProviderWithPreset = (p: Provider) => {
    setProvider(p);
    setEndpoint(PROVIDER_PRESETS[p].endpointHint);
    setRegion(PROVIDER_PRESETS[p].regionHint);
  };

  const resetForm = () => {
    setName("");
    setBucket("");
    setAccessKeyId("");
    setSecretKey("");
  };

  const handleAddProfile = async () => {
    const parsed = profileSchema.safeParse({ name, endpoint, bucket, region });
    if (!parsed.success) {
      toast.error(parsed.error.issues[0]?.message ?? "Validation failed");
      return;
    }
    if (
      profiles.some((p) => p.name.toLowerCase() === name.trim().toLowerCase())
    ) {
      toast.error(`A profile named '${name.trim()}' already exists`);
      return;
    }
    setSaving(true);
    try {
      await insertRow(
        ctx,
        PROFILES_TABLE,
        {
          name: name.trim(),
          provider,
          endpoint: endpoint.trim(),
          region: region.trim(),
          bucket: bucket.trim(),
          access_key_id: accessKeyId.trim(),
          secret_key: secretKey.trim(),
        },
        LOGGING_CLIENT,
      );
      resetForm();
      toast.success("S3 profile saved");
      void loadProfiles();
    } catch (err) {
      toast.error(
        err instanceof ApiError ? err.message : "Failed to save profile",
      );
    } finally {
      setSaving(false);
    }
  };

  const handleDeleteProfile = async () => {
    if (!deleteTarget?.id) return;
    setDeleting(true);
    try {
      await deleteRow(ctx, PROFILES_TABLE, deleteTarget.id, LOGGING_CLIENT);
      toast.success("Profile deleted");
      setDeleteTarget(null);
      if (activeProfile?.id === deleteTarget.id) {
        setActiveProfile(null);
        setObjects([]);
        setFolders([]);
      }
      void loadProfiles();
    } catch (err) {
      toast.error(
        err instanceof ApiError ? err.message : "Failed to delete profile",
      );
    } finally {
      setDeleting(false);
    }
  };

  const formatLatency = (ms: number) =>
    ms === 0
      ? "-"
      : ms < 1000
        ? `${Math.round(ms)}ms`
        : `${(ms / 1000).toFixed(1)}s`;

  return (
    <div className="flex flex-1 min-h-0 overflow-auto">
      <input
        ref={fileInputRef}
        type="file"
        className="hidden"
        onChange={handleUpload}
      />
      <div className="mx-auto w-full max-w-[1100px] px-3 sm:px-6 py-4 sm:py-8">
        <div className="flex items-start justify-between pb-6">
          <div>
            <h1 className="text-xl sm:text-2xl font-semibold tracking-tight">
              Storage
            </h1>
            <p className="mt-1 text-sm text-muted-foreground">
              Browse S3 buckets, manage files, and monitor database connectors.
            </p>
          </div>
        </div>

        <Tabs defaultValue="browser" className="space-y-0">
          <TabsList className="mb-5 h-10">
            <TabsTrigger value="browser">S3 Browser</TabsTrigger>
            <TabsTrigger value="s3-config">S3 Profiles</TabsTrigger>
            <TabsTrigger value="connectors">Connectors</TabsTrigger>
          </TabsList>

          {/* ── S3 Browser ──────────────────────────────────── */}
          <TabsContent value="browser" className="mt-0 space-y-4">
            {/* Profile selector */}
            {profiles.length === 0 && !profilesLoading ? (
              <div className="rounded-lg border border-border bg-card p-8 text-center text-sm text-muted-foreground">
                No storage profiles configured. Go to the S3 Profiles tab to add
                one.
              </div>
            ) : (
              <>
                <div className="flex flex-wrap items-center gap-2">
                  <span className="text-xs font-medium text-muted-foreground">
                    Profile:
                  </span>
                  {profiles.map((p) => (
                    <button
                      key={p.id ?? p.name}
                      onClick={() => handleSelectProfile(p)}
                      className={cn(
                        "rounded-full border px-3 py-1 text-xs font-medium transition-colors",
                        activeProfile?.id === p.id
                          ? "border-primary-border bg-primary-panel text-primary"
                          : "border-border text-muted-foreground hover:text-foreground hover:border-foreground-border",
                      )}
                    >
                      {p.name}
                      <span className="ml-1 text-muted-foreground-subtle">
                        {p.bucket}
                      </span>
                    </button>
                  ))}
                </div>

                {activeProfile && (
                  <section className="rounded-lg border border-border bg-card overflow-hidden">
                    {/* Toolbar */}
                    <div className="flex flex-wrap items-center gap-2 border-b border-border px-4 py-2.5">
                      {/* Breadcrumbs */}
                      <div className="flex items-center gap-1 text-xs min-w-0 flex-1">
                        <button
                          onClick={() => navigateToFolder("")}
                          className="text-muted-foreground hover:text-foreground transition-colors shrink-0"
                        >
                          <Home className="h-3.5 w-3.5" />
                        </button>
                        <span className="text-muted-foreground-dim shrink-0">
                          /
                        </span>
                        <span className="font-mono text-muted-foreground shrink-0">
                          {activeProfile.bucket}
                        </span>
                        {breadcrumbs.map((bc) => (
                          <span
                            key={bc.prefix}
                            className="flex items-center gap-1 shrink-0"
                          >
                            <ChevronRight className="h-3 w-3 text-muted-foreground-dim" />
                            <button
                              onClick={() => navigateToFolder(bc.prefix)}
                              className="text-foreground hover:text-primary transition-colors font-mono"
                            >
                              {bc.label}
                            </button>
                          </span>
                        ))}
                      </div>

                      <div className="flex items-center gap-1.5">
                        <Button
                          variant="outline"
                          size="sm"
                          className="h-7 text-body-sm"
                          onClick={() => setNewFolderOpen(true)}
                        >
                          <FolderPlus className="h-3 w-3" /> New folder
                        </Button>
                        <Button
                          size="sm"
                          className="h-7 text-body-sm"
                          onClick={() => fileInputRef.current?.click()}
                          disabled={uploading}
                        >
                          {uploading ? (
                            <Loader2 className="h-3 w-3 animate-spin" />
                          ) : (
                            <Upload className="h-3 w-3" />
                          )}
                          Upload
                        </Button>
                        <Button
                          variant="ghost"
                          size="sm"
                          className="h-7 w-7 p-0"
                          onClick={() =>
                            void browsePrefix(activeProfile, currentPrefix)
                          }
                          disabled={browseLoading}
                        >
                          {browseLoading ? (
                            <Loader2 className="h-3 w-3 animate-spin" />
                          ) : (
                            <RefreshCw className="h-3 w-3" />
                          )}
                        </Button>
                      </div>
                    </div>

                    {browseError && (
                      <div className="px-4 py-2 text-xs text-destructive border-b border-destructive-border bg-destructive-subtle">
                        {browseError}
                      </div>
                    )}

                    {/* File list */}
                    <div className="min-h-[300px]">
                      {browseLoading &&
                      objects.length === 0 &&
                      folders.length === 0 ? (
                        <div className="flex items-center justify-center py-16">
                          <Loader2 className="h-5 w-5 animate-spin text-primary" />
                        </div>
                      ) : folders.length === 0 && objects.length === 0 ? (
                        <div className="flex flex-col items-center justify-center py-16 text-sm text-muted-foreground gap-2">
                          <Folder className="h-8 w-8 opacity-20" />
                          <p>This folder is empty</p>
                          <div className="flex gap-2 mt-2">
                            <Button
                              variant="outline"
                              size="sm"
                              onClick={() => fileInputRef.current?.click()}
                            >
                              <Upload className="h-3 w-3" /> Upload file
                            </Button>
                            <Button
                              variant="outline"
                              size="sm"
                              onClick={() => setNewFolderOpen(true)}
                            >
                              <FolderPlus className="h-3 w-3" /> New folder
                            </Button>
                          </div>
                        </div>
                      ) : (
                        <table className="w-full text-sm">
                          <thead>
                            <tr className="border-b border-border bg-muted-panel text-left text-caption uppercase tracking-wider text-muted-foreground">
                              <th className="px-4 py-2 w-8" />
                              <th className="px-4 py-2">Name</th>
                              <th className="px-4 py-2 hidden sm:table-cell">
                                Size
                              </th>
                              <th className="px-4 py-2 hidden md:table-cell">
                                Modified
                              </th>
                              <th className="px-4 py-2 w-28" />
                            </tr>
                          </thead>
                          <tbody>
                            {currentPrefix && (
                              <tr
                                className="border-b border-border-muted hover:bg-accent-subtle cursor-pointer transition-colors"
                                onClick={navigateUp}
                              >
                                <td className="px-4 py-2">
                                  <Folder className="h-4 w-4 text-muted-foreground-subtle" />
                                </td>
                                <td className="px-4 py-2 font-mono text-xs text-muted-foreground">
                                  ..
                                </td>
                                <td className="hidden sm:table-cell" />
                                <td className="hidden md:table-cell" />
                                <td />
                              </tr>
                            )}
                            {folders.map((folder) => {
                              const display = folder
                                .replace(currentPrefix, "")
                                .replace(/\/$/, "");
                              return (
                                <tr
                                  key={folder}
                                  className="border-b border-border-muted hover:bg-accent-subtle cursor-pointer transition-colors"
                                  onClick={() => navigateToFolder(folder)}
                                >
                                  <td className="px-4 py-2">
                                    <Folder className="h-4 w-4 text-foreground-muted" />
                                  </td>
                                  <td className="px-4 py-2 font-mono text-xs font-medium">
                                    {display}/
                                  </td>
                                  <td className="px-4 py-2 text-xs text-muted-foreground hidden sm:table-cell">
                                    -
                                  </td>
                                  <td className="px-4 py-2 text-xs text-muted-foreground hidden md:table-cell">
                                    -
                                  </td>
                                  <td />
                                </tr>
                              );
                            })}
                            {objects.map((obj) => {
                              const fileName =
                                obj.key.split("/").pop() ?? obj.key;
                              const Icon = fileIcon(obj.key);
                              return (
                                <tr
                                  key={obj.key}
                                  className="border-b border-border-muted hover:bg-accent-subtle transition-colors group"
                                >
                                  <td className="px-4 py-2">
                                    <Icon className="h-4 w-4 text-muted-foreground-subtle" />
                                  </td>
                                  <td
                                    className="px-4 py-2 font-mono text-xs truncate max-w-[300px]"
                                    title={obj.key}
                                  >
                                    {fileName}
                                  </td>
                                  <td className="px-4 py-2 text-xs text-muted-foreground tabular-nums hidden sm:table-cell">
                                    {formatBytes(obj.size)}
                                  </td>
                                  <td className="px-4 py-2 text-xs text-muted-foreground hidden md:table-cell">
                                    {obj.last_modified
                                      ? new Date(
                                          obj.last_modified,
                                        ).toLocaleString()
                                      : "-"}
                                  </td>
                                  <td className="px-4 py-2">
                                    <div className="flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
                                      <button
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          void handlePreview(obj);
                                        }}
                                        className="p-1 rounded hover:bg-accent transition-colors text-muted-foreground hover:text-foreground"
                                        title="Preview"
                                      >
                                        <Eye className="h-3.5 w-3.5" />
                                      </button>
                                      <button
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          void handleDownload(obj);
                                        }}
                                        className="p-1 rounded hover:bg-accent transition-colors text-muted-foreground hover:text-foreground"
                                        title="Download"
                                      >
                                        <Download className="h-3.5 w-3.5" />
                                      </button>
                                      <button
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          setDeleteObjectTarget(obj);
                                        }}
                                        className="p-1 rounded hover:bg-destructive/10 transition-colors text-muted-foreground hover:text-destructive"
                                        title="Delete"
                                      >
                                        <Trash2 className="h-3.5 w-3.5" />
                                      </button>
                                    </div>
                                  </td>
                                </tr>
                              );
                            })}
                          </tbody>
                        </table>
                      )}
                    </div>

                    <div className="border-t border-border px-4 py-2 text-caption text-muted-foreground flex items-center justify-between">
                      <span>
                        {folders.length} folder{folders.length !== 1 ? "s" : ""}
                        , {objects.length} file{objects.length !== 1 ? "s" : ""}
                      </span>
                      <span className="font-mono">
                        {activeProfile.bucket}/{currentPrefix}
                      </span>
                    </div>
                  </section>
                )}
              </>
            )}
          </TabsContent>

          {/* ── S3 Profiles tab ────────────────────────────── */}
          <TabsContent value="s3-config" className="mt-0 space-y-5">
            <section className="rounded-lg border border-border bg-card overflow-hidden">
              <div className="border-b border-border px-5 py-4">
                <p className="text-base font-semibold">New S3 Connection</p>
                <p className="text-sm text-muted-foreground mt-1">
                  Connect a bucket using AWS S3, Minio, Hetzner, or Cloudflare
                  R2.
                </p>
              </div>
              <div className="grid gap-4 px-5 py-5 md:grid-cols-2">
                <div>
                  <label className="text-xs text-muted-foreground">
                    Provider
                  </label>
                  <select
                    value={provider}
                    onChange={(e) =>
                      setProviderWithPreset(e.target.value as Provider)
                    }
                    className="mt-1 h-9 w-full rounded-md border border-border bg-background px-3 text-sm"
                  >
                    <option value="aws-s3">Amazon S3</option>
                    <option value="minio">Minio</option>
                    <option value="hetzner">Hetzner Object Storage</option>
                    <option value="cloudflare-r2">Cloudflare R2</option>
                  </select>
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">
                    Profile name
                  </label>
                  <Input
                    value={name}
                    onChange={(e) => setName(e.target.value)}
                    className="mt-1"
                    placeholder="primary-storage"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">
                    Endpoint
                  </label>
                  <Input
                    value={endpoint}
                    onChange={(e) => setEndpoint(e.target.value)}
                    className="mt-1 font-mono text-xs"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">
                    Region
                  </label>
                  <Input
                    value={region}
                    onChange={(e) => setRegion(e.target.value)}
                    className="mt-1 font-mono text-xs"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">
                    Bucket
                  </label>
                  <Input
                    value={bucket}
                    onChange={(e) => setBucket(e.target.value)}
                    className="mt-1 font-mono text-xs"
                    placeholder="athena-prod-backups"
                  />
                </div>
                <div>
                  <label className="text-xs text-muted-foreground">
                    Access key ID
                  </label>
                  <Input
                    value={accessKeyId}
                    onChange={(e) => setAccessKeyId(e.target.value)}
                    className="mt-1 font-mono text-xs"
                    placeholder="AKIA..."
                  />
                </div>
                <div className="md:col-span-2">
                  <label className="text-xs text-muted-foreground">
                    Secret key
                  </label>
                  <Input
                    value={secretKey}
                    onChange={(e) => setSecretKey(e.target.value)}
                    className="mt-1 font-mono text-xs"
                    type="password"
                    placeholder="••••••••••••••"
                  />
                </div>
              </div>
              <div className="flex items-center justify-end gap-2 border-t border-border px-5 py-4">
                <Button variant="outline" size="sm" onClick={resetForm}>
                  Cancel
                </Button>
                <Button size="sm" onClick={handleAddProfile} disabled={saving}>
                  {saving ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                  ) : (
                    <Plus className="h-3.5 w-3.5" />
                  )}{" "}
                  Save profile
                </Button>
              </div>
            </section>

            <section className="rounded-lg border border-border bg-card overflow-hidden">
              <div className="flex items-center justify-between border-b border-border px-5 py-4">
                <div>
                  <p className="text-sm font-semibold">Saved Profiles</p>
                  <p className="text-xs text-muted-foreground mt-1">
                    S3-compatible storage profiles.
                  </p>
                </div>
                <Button
                  size="sm"
                  variant="outline"
                  onClick={() => void loadProfiles()}
                  disabled={profilesLoading}
                >
                  {profilesLoading ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                  ) : (
                    <RefreshCw className="h-3.5 w-3.5" />
                  )}{" "}
                  Refresh
                </Button>
              </div>
              {profilesLoading && profiles.length === 0 ? (
                <div className="flex items-center justify-center py-12">
                  <Loader2 className="h-5 w-5 animate-spin text-primary" />
                </div>
              ) : profiles.length === 0 ? (
                <div className="px-5 py-8 text-sm text-muted-foreground text-center">
                  No profiles yet. Add one above.
                </div>
              ) : (
                <div className="overflow-x-auto">
                  <table className="w-full text-sm">
                    <thead>
                      <tr className="border-b border-border bg-muted-panel text-left text-body-sm uppercase tracking-wider text-muted-foreground">
                        <th className="px-5 py-2">Name</th>
                        <th className="px-5 py-2">Provider</th>
                        <th className="px-5 py-2 hidden sm:table-cell">
                          Endpoint
                        </th>
                        <th className="px-5 py-2">Bucket</th>
                        <th className="px-5 py-2 hidden md:table-cell">
                          Region
                        </th>
                        <th className="px-5 py-2 w-20" />
                      </tr>
                    </thead>
                    <tbody>
                      {profiles.map((p) => (
                        <tr
                          key={p.id ?? p.name}
                          className="border-b border-border-subtle last:border-b-0 hover:bg-accent-subtle transition-colors"
                        >
                          <td className="px-5 py-3 font-medium">{p.name}</td>
                          <td className="px-5 py-3">
                            <Badge variant="secondary">{p.provider}</Badge>
                          </td>
                          <td className="px-5 py-3 font-mono text-xs text-muted-foreground hidden sm:table-cell max-w-[200px] truncate">
                            {p.endpoint}
                          </td>
                          <td className="px-5 py-3 font-mono text-xs">
                            {p.bucket}
                          </td>
                          <td className="px-5 py-3 font-mono text-xs hidden md:table-cell">
                            {p.region}
                          </td>
                          <td className="px-5 py-3 flex gap-1">
                            <button
                              onClick={() => handleSelectProfile(p)}
                              className="p-1 rounded text-muted-foreground-subtle hover:text-primary hover:bg-primary-muted transition-colors"
                              title="Browse bucket"
                            >
                              <Eye className="h-3.5 w-3.5" />
                            </button>
                            <button
                              onClick={() => setDeleteTarget(p)}
                              className="p-1 rounded text-muted-foreground-dim hover:text-destructive hover:bg-destructive/10 transition-colors"
                              title="Delete"
                            >
                              <Trash2 className="h-3.5 w-3.5" />
                            </button>
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </section>
          </TabsContent>

          {/* ── Connectors tab ──────────────────────────────── */}
          <TabsContent value="connectors" className="mt-0 space-y-5">
            <section className="rounded-lg border border-border bg-card overflow-hidden">
              <div className="flex items-center justify-between border-b border-border px-5 py-4">
                <div>
                  <p className="text-base font-semibold">Database Connectors</p>
                  <p className="text-xs text-muted-foreground mt-1">
                    Live view of configured Postgres clients. Health checks
                    every 10s.
                  </p>
                </div>
                <div className="flex items-center gap-2">
                  <Button
                    variant={autoRefresh ? "default" : "outline"}
                    size="sm"
                    onClick={() => setAutoRefresh((v) => !v)}
                  >
                    <Zap className="h-3.5 w-3.5" /> Live{" "}
                    {autoRefresh ? "On" : "Off"}
                  </Button>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => {
                      void loadConnectors();
                      void healthCheckConnectors();
                    }}
                    disabled={connectorsLoading}
                  >
                    {connectorsLoading ? (
                      <Loader2 className="h-3.5 w-3.5 animate-spin" />
                    ) : (
                      <RefreshCw className="h-3.5 w-3.5" />
                    )}{" "}
                    Refresh
                  </Button>
                </div>
              </div>
              {connectorsLoading && clients.length === 0 ? (
                <div className="flex items-center justify-center py-12">
                  <Loader2 className="h-5 w-5 animate-spin text-primary" />
                </div>
              ) : clients.length === 0 ? (
                <div className="px-5 py-12 text-center text-sm text-muted-foreground">
                  No connectors found.
                </div>
              ) : (
                <div className="divide-y divide-border">
                  {clients.map((clientName) => {
                    const status = connectorStatuses.get(clientName);
                    const isActive = clientName === selectedClient;
                    return (
                      <div
                        key={clientName}
                        className={cn(
                          "flex items-center gap-4 px-5 py-3.5 transition-colors",
                          isActive && "bg-primary-subtle",
                        )}
                      >
                        <div
                          className={cn(
                            "flex h-8 w-8 items-center justify-center rounded-lg border",
                            status?.ok
                              ? "border-success-border bg-success-muted"
                              : "border-destructive-border bg-destructive-muted",
                          )}
                        >
                          {status?.ok ? (
                            <Wifi className="h-4 w-4 text-success" />
                          ) : (
                            <WifiOff className="h-4 w-4 text-destructive" />
                          )}
                        </div>
                        <div className="flex-1 min-w-0">
                          <div className="flex items-center gap-2">
                            <span className="text-sm font-medium text-foreground truncate">
                              {clientName}
                            </span>
                            {isActive && (
                              <Badge className="text-tiny px-1.5 py-0 bg-primary-muted text-primary border border-primary-border">
                                ACTIVE
                              </Badge>
                            )}
                          </div>
                          <p className="text-body-sm text-muted-foreground mt-0.5">
                            {status?.version
                              ? `v${status.version}`
                              : "Postgres"}
                            {status?.lastChecked
                              ? ` · ${new Date(status.lastChecked).toLocaleTimeString()}`
                              : ""}
                          </p>
                        </div>
                        <div className="flex items-center gap-3 shrink-0">
                          <div className="text-right">
                            <p
                              className={cn(
                                "text-xs font-medium tabular-nums",
                                status?.ok
                                  ? "text-success"
                                  : "text-destructive",
                              )}
                            >
                              {status?.ok ? "Connected" : "Unreachable"}
                            </p>
                            <p className="text-caption text-muted-foreground tabular-nums">
                              {formatLatency(status?.latencyMs ?? 0)}
                            </p>
                          </div>
                          <div
                            className={cn(
                              "h-2.5 w-2.5 rounded-full",
                              status?.ok
                                ? "bg-success animate-pulse"
                                : "bg-destructive",
                            )}
                          />
                        </div>
                      </div>
                    );
                  })}
                </div>
              )}
              <div className="border-t border-border px-5 py-2.5 text-caption text-muted-foreground flex items-center justify-between">
                <span>
                  {clients.length} connector{clients.length !== 1 ? "s" : ""}
                </span>
                <span>{autoRefresh ? "Auto-refresh 10s" : "Paused"}</span>
              </div>
            </section>
          </TabsContent>
        </Tabs>
      </div>

      {/* Delete profile dialog */}
      <Dialog
        open={!!deleteTarget}
        onOpenChange={(v) => !v && setDeleteTarget(null)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete storage profile</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete{" "}
              <strong>{deleteTarget?.name}</strong>?
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDeleteTarget(null)}>
              Cancel
            </Button>
            <Button
              variant="destructive"
              onClick={handleDeleteProfile}
              disabled={deleting}
            >
              {deleting && <Loader2 className="h-3 w-3 animate-spin" />} Delete
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Delete object dialog */}
      <Dialog
        open={!!deleteObjectTarget}
        onOpenChange={(v) => !v && setDeleteObjectTarget(null)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete object</DialogTitle>
            <DialogDescription>
              Delete{" "}
              <code className="font-mono text-xs bg-muted px-1 py-0.5 rounded">
                {deleteObjectTarget?.key.split("/").pop()}
              </code>{" "}
              from the bucket?
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => setDeleteObjectTarget(null)}
            >
              Cancel
            </Button>
            <Button
              variant="destructive"
              onClick={handleDeleteObject}
              disabled={deletingObject}
            >
              {deletingObject && <Loader2 className="h-3 w-3 animate-spin" />}{" "}
              Delete
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* New folder dialog */}
      <Dialog open={newFolderOpen} onOpenChange={setNewFolderOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Create folder</DialogTitle>
            <DialogDescription>
              New folder under{" "}
              <code className="font-mono text-xs bg-muted px-1 py-0.5 rounded">
                {activeProfile?.bucket}/{currentPrefix}
              </code>
            </DialogDescription>
          </DialogHeader>
          <Input
            value={newFolderName}
            onChange={(e) => setNewFolderName(e.target.value)}
            placeholder="folder-name"
            className="font-mono text-sm"
            onKeyDown={(e) => e.key === "Enter" && void handleCreateFolder()}
            autoFocus
          />
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => {
                setNewFolderOpen(false);
                setNewFolderName("");
              }}
            >
              Cancel
            </Button>
            <Button
              onClick={() => void handleCreateFolder()}
              disabled={creatingFolder || !newFolderName.trim()}
            >
              {creatingFolder && <Loader2 className="h-3 w-3 animate-spin" />}{" "}
              Create
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
