"use client";

import { useQuery } from "@tanstack/react-query";
import { Button } from "@workspace/ui/components/button";
import { Checkbox } from "@workspace/ui/components/checkbox";
import { Label } from "@workspace/ui/components/label";
import { ScrollArea } from "@workspace/ui/components/scroll-area";
import {
  Sheet,
  SheetContent,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@workspace/ui/components/sheet";
import { Switch } from "@workspace/ui/components/switch";
import { Combobox } from "@workspace/ui/composed/combobox";
import { EnhancedInput } from "@workspace/ui/composed/enhanced-input";
import TagInput from "@workspace/ui/composed/tag-input";
import {
  getGroupConfig,
  getNodeGroupList,
} from "@workspace/ui/services/admin/group";
import { updateNode } from "@workspace/ui/services/admin/server";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { useNode } from "@/stores/node";
import { useServer } from "@/stores/server";

type FieldKey =
  | "name"
  | "enabled"
  | "tags"
  | "server_id"
  | "protocol"
  | "address"
  | "port"
  | "node_group_ids";

interface BatchPatch {
  name?: string;
  enabled?: boolean;
  tags?: string[];
  server_id?: number;
  protocol?: string;
  address?: string;
  port?: number;
  node_group_ids?: number[];
}

export default function NodeBatchSheet({
  rows,
  onSuccess,
}: {
  rows: API.Node[];
  onSuccess: () => void;
}) {
  const { t } = useTranslation("nodes");
  const [open, setOpen] = useState(false);
  const [loading, setLoading] = useState(false);

  // Which fields are active (will be applied)
  const [enabledFields, setEnabledFields] = useState<Set<FieldKey>>(new Set());

  // Patch values
  const [patch, setPatch] = useState<BatchPatch>({
    name: "",
    enabled: true,
    tags: [],
    server_id: undefined,
    protocol: undefined,
    address: "",
    port: undefined,
    node_group_ids: [],
  });

  const { servers, getAvailableProtocols } = useServer();
  const { tags: existingTags } = useNode();

  const { data: nodeGroupsData } = useQuery({
    queryKey: ["nodeGroups"],
    queryFn: async () => {
      const { data } = await getNodeGroupList({ page: 1, size: 1000 });
      return data.data?.list || [];
    },
  });

  const { data: groupConfigData } = useQuery({
    queryKey: ["groupConfig"],
    queryFn: async () => {
      const { data } = await getGroupConfig();
      return data.data;
    },
  });

  const isGroupEnabled = groupConfigData?.enabled;

  const availableProtocols = getAvailableProtocols(patch.server_id);

  function toggleField(key: FieldKey) {
    setEnabledFields((prev) => {
      const next = new Set(prev);
      if (next.has(key)) {
        next.delete(key);
        // When disabling server_id, also disable protocol (it depends on server selection)
        if (key === "server_id") next.delete("protocol");
      } else {
        next.add(key);
        // When enabling server_id, auto-enable protocol as it must be set together
        if (key === "server_id") next.add("protocol");
      }
      return next;
    });
  }

  function isEnabled(key: FieldKey) {
    return enabledFields.has(key);
  }

  async function handleSubmit() {
    if (rows.length === 0) return;
    if (enabledFields.size === 0) {
      toast.warning(
        t(
          "batch_no_fields_selected",
          "Please select at least one field to update"
        )
      );
      return;
    }

    // Validate enabled fields before submitting
    if (enabledFields.has("name") && !patch.name?.trim()) {
      toast.warning(t("batch_name_required", "Name cannot be empty"));
      return;
    }
    if (enabledFields.has("server_id") && !patch.server_id) {
      toast.warning(t("batch_server_required", "Please select a server"));
      return;
    }
    if (enabledFields.has("protocol") && !patch.protocol) {
      toast.warning(t("batch_protocol_required", "Please select a protocol"));
      return;
    }
    if (
      enabledFields.has("port") &&
      (!patch.port || patch.port < 1 || patch.port > 65_535)
    ) {
      toast.warning(
        t("batch_port_invalid", "Port must be between 1 and 65535")
      );
      return;
    }

    const activePatch: Partial<BatchPatch> = {};
    for (const key of enabledFields) {
      (activePatch as any)[key] = (patch as any)[key];
    }

    setLoading(true);
    try {
      const results = await Promise.allSettled(
        rows.map((row) => {
          const body: API.UpdateNodeRequest = {
            id: row.id,
            name: row.name,
            tags: row.tags,
            port: row.port,
            address: row.address,
            server_id: row.server_id,
            protocol: row.protocol,
            enabled: row.enabled,
            ...activePatch,
          } as any;
          return updateNode(body);
        })
      );

      const succeeded = results.filter((r) => r.status === "fulfilled").length;
      const failed = results.filter((r) => r.status === "rejected").length;

      if (failed === 0) {
        toast.success(
          t("batch_updated", "Updated {{count}} nodes", { count: succeeded })
        );
        setOpen(false);
        setEnabledFields(new Set());
        onSuccess();
      } else if (succeeded > 0) {
        toast.warning(
          t("batch_partial", "{{succeeded}} updated, {{failed}} failed", {
            succeeded,
            failed,
          })
        );
        onSuccess();
      } else {
        toast.error(t("batch_update_failed", "Batch update failed"));
      }
    } finally {
      setLoading(false);
    }
  }

  function handleOpen() {
    setEnabledFields(new Set());
    setPatch({
      name: "",
      enabled: true,
      tags: [],
      server_id: undefined,
      protocol: undefined,
      address: "",
      port: undefined,
      node_group_ids: [],
    });
    setOpen(true);
  }

  return (
    <Sheet onOpenChange={setOpen} open={open}>
      <SheetTrigger asChild>
        <Button onClick={handleOpen} variant="outline">
          {t("batch_update", "Batch Update")}
        </Button>
      </SheetTrigger>

      <SheetContent className="w-[560px] max-w-full">
        <SheetHeader>
          <SheetTitle>
            {t("batch_update_title", "Batch Update ({{count}} nodes)", {
              count: rows.length,
            })}
          </SheetTitle>
        </SheetHeader>

        <ScrollArea className="h-[calc(100dvh-48px-36px-36px-env(safe-area-inset-top))] px-6 pt-4">
          <p className="mb-4 text-muted-foreground text-sm">
            {t(
              "batch_update_desc",
              "Check the fields you want to overwrite. Unchecked fields will keep their original values."
            )}
          </p>

          <div className="space-y-5">
            {/* name */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("name")}
                id="batch-name"
                onCheckedChange={() => toggleField("name")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={isEnabled("name") ? "" : "text-muted-foreground"}
                  htmlFor="batch-name"
                >
                  {t("name", "Name")}
                </Label>
                <div
                  className={
                    isEnabled("name") ? "" : "pointer-events-none opacity-40"
                  }
                >
                  <EnhancedInput
                    onValueChange={(v) =>
                      setPatch((p) => ({ ...p, name: String(v ?? "") }))
                    }
                    value={patch.name ?? ""}
                  />
                </div>
              </div>
            </div>

            {/* enabled */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("enabled")}
                id="batch-enabled"
                onCheckedChange={() => toggleField("enabled")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={
                    isEnabled("enabled") ? "" : "text-muted-foreground"
                  }
                  htmlFor="batch-enabled"
                >
                  {t("enabled", "Enabled")}
                </Label>
                <div
                  className={
                    isEnabled("enabled") ? "" : "pointer-events-none opacity-40"
                  }
                >
                  <Switch
                    checked={!!patch.enabled}
                    onCheckedChange={(v) =>
                      setPatch((p) => ({ ...p, enabled: v }))
                    }
                  />
                </div>
              </div>
            </div>

            {/* tags */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("tags")}
                id="batch-tags"
                onCheckedChange={() => toggleField("tags")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={isEnabled("tags") ? "" : "text-muted-foreground"}
                  htmlFor="batch-tags"
                >
                  {t("tags", "Tags")}
                </Label>
                <div
                  className={
                    isEnabled("tags") ? "" : "pointer-events-none opacity-40"
                  }
                >
                  <TagInput
                    onChange={(v) => setPatch((p) => ({ ...p, tags: v }))}
                    options={existingTags || []}
                    placeholder={t(
                      "tags_placeholder",
                      "Use Enter or comma (,) to add"
                    )}
                    value={patch.tags || []}
                  />
                </div>
              </div>
            </div>

            {/* server_id */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("server_id")}
                id="batch-server"
                onCheckedChange={() => toggleField("server_id")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={
                    isEnabled("server_id") ? "" : "text-muted-foreground"
                  }
                  htmlFor="batch-server"
                >
                  {t("server", "Server")}
                </Label>
                <div
                  className={
                    isEnabled("server_id")
                      ? ""
                      : "pointer-events-none opacity-40"
                  }
                >
                  <Combobox<number, false>
                    onChange={(v) => {
                      setPatch((p) => ({
                        ...p,
                        server_id: v ?? undefined,
                        protocol: undefined,
                      }));
                    }}
                    options={servers.map((s) => ({
                      value: s.id,
                      label: `${s.name} (${(s.address as any) || ""})`,
                    }))}
                    placeholder={t("select_server", "Select server…")}
                    value={patch.server_id}
                  />
                </div>
              </div>
            </div>

            {/* protocol */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("protocol")}
                id="batch-protocol"
                onCheckedChange={() => toggleField("protocol")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={
                    isEnabled("protocol") ? "" : "text-muted-foreground"
                  }
                  htmlFor="batch-protocol"
                >
                  {t("protocol", "Protocol")}
                </Label>
                <div
                  className={
                    isEnabled("protocol")
                      ? ""
                      : "pointer-events-none opacity-40"
                  }
                >
                  <Combobox<string, false>
                    onChange={(v) =>
                      setPatch((p) => ({ ...p, protocol: v ?? undefined }))
                    }
                    options={availableProtocols.map((p) => ({
                      value: p.protocol,
                      label: `${p.protocol}${p.port ? ` (${p.port})` : ""}`,
                    }))}
                    placeholder={t("select_protocol", "Select protocol…")}
                    value={patch.protocol}
                  />
                </div>
              </div>
            </div>

            {/* address */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("address")}
                id="batch-address"
                onCheckedChange={() => toggleField("address")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={
                    isEnabled("address") ? "" : "text-muted-foreground"
                  }
                  htmlFor="batch-address"
                >
                  {t("address", "Address")}
                </Label>
                <div
                  className={
                    isEnabled("address") ? "" : "pointer-events-none opacity-40"
                  }
                >
                  <EnhancedInput
                    onValueChange={(v) =>
                      setPatch((p) => ({ ...p, address: String(v ?? "") }))
                    }
                    value={patch.address ?? ""}
                  />
                </div>
              </div>
            </div>

            {/* port */}
            <div className="flex items-start gap-3">
              <Checkbox
                checked={isEnabled("port")}
                id="batch-port"
                onCheckedChange={() => toggleField("port")}
              />
              <div className="flex-1 space-y-1.5">
                <Label
                  className={isEnabled("port") ? "" : "text-muted-foreground"}
                  htmlFor="batch-port"
                >
                  {t("port", "Port")}
                </Label>
                <div
                  className={
                    isEnabled("port") ? "" : "pointer-events-none opacity-40"
                  }
                >
                  <EnhancedInput
                    max={65_535}
                    min={1}
                    onValueChange={(v) =>
                      setPatch((p) => ({
                        ...p,
                        port: v ? Number(v) : undefined,
                      }))
                    }
                    placeholder="1-65535"
                    type="number"
                    value={patch.port ?? ""}
                  />
                </div>
              </div>
            </div>

            {/* node_group_ids — only when group feature is enabled */}
            {isGroupEnabled && (
              <div className="flex items-start gap-3">
                <Checkbox
                  checked={isEnabled("node_group_ids")}
                  id="batch-groups"
                  onCheckedChange={() => toggleField("node_group_ids")}
                />
                <div className="flex-1 space-y-1.5">
                  <Label
                    className={
                      isEnabled("node_group_ids") ? "" : "text-muted-foreground"
                    }
                    htmlFor="batch-groups"
                  >
                    {t("nodeGroups", "Node Groups")}
                  </Label>
                  <div
                    className={
                      isEnabled("node_group_ids")
                        ? "grid grid-cols-2 gap-2"
                        : "pointer-events-none grid grid-cols-2 gap-2 opacity-40"
                    }
                  >
                    {nodeGroupsData?.map((g) => {
                      const ids = patch.node_group_ids || [];
                      const checked = ids.includes(g.id);
                      return (
                        <div className="flex items-center space-x-2" key={g.id}>
                          <Checkbox
                            checked={checked}
                            id={`batch-group-${g.id}`}
                            onCheckedChange={(c) => {
                              setPatch((p) => {
                                const current = p.node_group_ids || [];
                                return {
                                  ...p,
                                  node_group_ids: c
                                    ? [...current, g.id]
                                    : current.filter((id) => id !== g.id),
                                };
                              });
                            }}
                          />
                          <Label htmlFor={`batch-group-${g.id}`}>
                            {g.name}
                          </Label>
                        </div>
                      );
                    })}
                  </div>
                </div>
              </div>
            )}
          </div>
        </ScrollArea>

        <SheetFooter className="flex-row justify-end gap-2 pt-3">
          <Button
            disabled={loading}
            onClick={() => setOpen(false)}
            variant="outline"
          >
            {t("cancel", "Cancel")}
          </Button>
          <Button disabled={loading} onClick={handleSubmit}>
            {t("confirm", "Confirm")}
          </Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}
