import { useEffect, useMemo, useRef, useState } from "react";
import { qk } from "../lib/queryKeys";
import { useTranslation } from "react-i18next";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Check, Copy, Link2, Lock, Trash2, UserPlus, Eye } from "lucide-react";
import clsx from "clsx";
import Modal from "./Modal";
import { useConfirm } from "./ConfirmProvider";
import { notify } from "../lib/notifications";
import { copyText } from "../lib/clipboard";
import { api, type DownloadJob, type ShareLink } from "../lib/api";
import { inputCls, btnCls } from "./ui/form";
const EXPIRY_DAYS = [null, 1, 7, 30] as const;

// --- share with a registered user (ACL) -----------------------------------------------------

function UserShare({ job }: { job: DownloadJob }) {
  const { t } = useTranslation();
  const [q, setQ] = useState("");
  const [open, setOpen] = useState(false);
  const recipients = useQuery({ queryKey: qk.shareRecipients(), queryFn: api.shareRecipients });
  const list = recipients.data ?? [];
  const filtered = useMemo(() => {
    const s = q.trim().toLowerCase();
    if (!s) return list.slice(0, 8);
    return list
      .filter(
        (u) =>
          u.email.toLowerCase().includes(s) || (u.display_name ?? "").toLowerCase().includes(s),
      )
      .slice(0, 8);
  }, [q, list]);

  const share = useMutation({
    mutationFn: (email: string) => api.shareDownload(job.id, email),
    onSuccess: (r) => {
      notify({ level: "success", message: t("downloads.share.done", { email: r.shared_with }) });
      setQ("");
      setOpen(false);
    },
    onError: () => notify({ level: "error", message: t("downloads.share.failed") }),
  });

  return (
    <div>
      <div className="flex items-center gap-2 text-sm font-medium mb-1">
        <UserPlus className="w-4 h-4 text-muted" /> {t("downloads.share.userSection")}
      </div>
      <p className="text-xs text-muted mb-2">{t("downloads.share.userHint")}</p>
      <div className="relative">
        <input
          value={q}
          onChange={(e) => {
            setQ(e.target.value);
            setOpen(true);
          }}
          onFocus={() => setOpen(true)}
          // Close on blur, but after a tick so a click on a dropdown row still registers.
          onBlur={() => setTimeout(() => setOpen(false), 150)}
          placeholder={t("downloads.share.pickPlaceholder")}
          className={inputCls}
        />
        {open && filtered.length > 0 && (
          <div className="absolute z-base mt-1 w-full rounded-lg glass-menu shadow-xl overflow-hidden">
            {filtered.map((u) => (
              <button
                key={u.id}
                onClick={() => share.mutate(u.email)}
                disabled={share.isPending}
                className="w-full text-left px-3 py-2 text-sm hover:bg-surface transition flex flex-col"
              >
                <span className="truncate">{u.display_name || u.email}</span>
                {u.display_name && <span className="text-xs text-muted truncate">{u.email}</span>}
              </button>
            ))}
          </div>
        )}
      </div>
      {recipients.data && list.length === 0 && (
        <p className="text-xs text-muted mt-1">{t("downloads.share.noUsers")}</p>
      )}
    </div>
  );
}

// --- share by public link -------------------------------------------------------------------

function LinkRow({ link, onChanged }: { link: ShareLink; onChanged: () => void }) {
  const { t } = useTranslation();
  const confirm = useConfirm();
  const [copied, setCopied] = useState(false);
  const [editPass, setEditPass] = useState(false);
  const [newPass, setNewPass] = useState("");
  const fullUrl = window.location.origin + link.url;

  const copy = async () => {
    if (await copyText(fullUrl)) {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    } else {
      notify({ level: "error", message: t("downloads.share.copyFailed") });
    }
  };
  const toggle = useMutation({
    mutationFn: () => api.updateDownloadLink(link.id, { allow_download: !link.allow_download }),
    onSuccess: onChanged,
  });
  const revoke = useMutation({
    mutationFn: () => api.revokeDownloadLink(link.id),
    onSuccess: onChanged,
  });
  // Set / change / clear the link password. Rotating (or clearing) it bumps the link's
  // password_version server-side, which invalidates any watch grant issued under the old password.
  const savePass = useMutation({
    mutationFn: (pw: string) => api.updateDownloadLink(link.id, { password: pw }),
    onSuccess: () => {
      setEditPass(false);
      setNewPass("");
      onChanged();
    },
  });

  const badges: string[] = [];
  if (link.has_password) badges.push(t("downloads.share.hasPassword"));
  if (link.allow_download) badges.push(t("downloads.share.downloadable"));
  if (link.expires_at)
    badges.push(
      t("downloads.share.expiresOn", { date: new Date(link.expires_at).toLocaleDateString() }),
    );

  return (
    <div className="rounded-lg glass-card p-2.5 space-y-2">
      <div className="flex items-center gap-2">
        <Link2 className="w-4 h-4 text-muted shrink-0" />
        <input
          readOnly
          value={fullUrl}
          className="flex-1 min-w-0 bg-transparent text-xs text-muted truncate outline-none"
        />
        <button
          onClick={copy}
          title={t("downloads.share.copy")}
          className="p-1.5 rounded-md hover:bg-surface text-muted hover:text-fg transition"
        >
          {copied ? <Check className="w-4 h-4 text-emerald-400" /> : <Copy className="w-4 h-4" />}
        </button>
        <button
          onClick={() => {
            setNewPass("");
            setEditPass((v) => !v);
          }}
          title={
            link.has_password
              ? t("downloads.share.changePassword")
              : t("downloads.share.setPassword")
          }
          className={clsx(
            "p-1.5 rounded-md hover:bg-surface transition",
            link.has_password ? "text-accent" : "text-muted hover:text-fg",
          )}
        >
          <Lock className="w-4 h-4" />
        </button>
        <button
          onClick={async () => {
            if (
              await confirm({
                title: t("downloads.share.revoke"),
                message: t("downloads.share.revokeConfirm"),
                confirmLabel: t("downloads.share.revoke"),
                danger: true,
              })
            )
              revoke.mutate();
          }}
          title={t("downloads.share.revoke")}
          className="p-1.5 rounded-md hover:bg-surface text-muted hover:text-red-400 transition"
        >
          <Trash2 className="w-4 h-4" />
        </button>
      </div>
      <div className="flex items-center gap-2 text-xs text-muted flex-wrap">
        <span className="inline-flex items-center gap-1">
          <Eye className="w-3 h-3" /> {t("downloads.share.views", { n: link.view_count })}
        </span>
        {badges.map((b) => (
          <span key={b} className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded bg-surface">
            {b === t("downloads.share.hasPassword") && <Lock className="w-3 h-3" />}
            {b}
          </span>
        ))}
        <div className="flex-1" />
        <label className="inline-flex items-center gap-1.5 cursor-pointer">
          <input type="checkbox" checked={link.allow_download} onChange={() => toggle.mutate()} />
          {t("downloads.share.allowDownload")}
        </label>
      </div>
      {editPass && (
        <div className="flex items-center gap-2">
          <input
            type="password"
            autoComplete="new-password"
            value={newPass}
            onChange={(e) => setNewPass(e.target.value)}
            onKeyDown={(e) =>
              e.key === "Enter" && newPass.trim() && savePass.mutate(newPass.trim())
            }
            placeholder={t(
              link.has_password ? "downloads.share.newPassword" : "downloads.share.setPassword",
            )}
            className="flex-1 min-w-0 bg-card border border-border rounded-md px-2 py-1 text-xs outline-none focus:border-accent"
          />
          <button
            onClick={() => savePass.mutate(newPass.trim())}
            disabled={savePass.isPending || !newPass.trim()}
            className="px-2 py-1 rounded-md text-xs font-semibold bg-accent text-accent-fg hover:opacity-90 disabled:opacity-40 transition"
          >
            {t("downloads.share.savePassword")}
          </button>
          {link.has_password && (
            <button
              onClick={async () => {
                if (
                  await confirm({
                    title: t("downloads.share.removePassword"),
                    message: t("downloads.share.removePasswordConfirm"),
                    confirmLabel: t("downloads.share.removePassword"),
                    danger: true,
                  })
                )
                  savePass.mutate("");
              }}
              disabled={savePass.isPending}
              className="px-2 py-1 rounded-md text-xs text-muted hover:text-red-400 transition"
            >
              {t("downloads.share.removePassword")}
            </button>
          )}
        </div>
      )}
    </div>
  );
}

function LinkShare({ job }: { job: DownloadJob }) {
  const { t } = useTranslation();
  const qc = useQueryClient();
  const links = useQuery({
    queryKey: qk.downloadLinks(job.id),
    queryFn: () => api.downloadLinks(job.id),
  });
  const [creating, setCreating] = useState(false);
  const [allowDownload, setAllowDownload] = useState(false);
  const [expiryDays, setExpiryDays] = useState<number | null>(null);
  const [password, setPassword] = useState("");
  const invalidate = () => qc.invalidateQueries({ queryKey: qk.downloadLinks(job.id) });

  const create = useMutation({
    mutationFn: () =>
      api.createDownloadLink(job.id, {
        allow_download: allowDownload,
        expires_days: expiryDays,
        password: password.trim() || undefined,
      }),
    onSuccess: () => {
      invalidate();
      setCreating(false);
      setAllowDownload(false);
      setExpiryDays(null);
      setPassword("");
    },
  });

  // Open with a link already generated: sharing is almost always the goal, so mint a default
  // (no password, no expiry, view-only) link the moment the dialog finds none — as if the user
  // had pressed "New link" → "Create". All further controls (password, download toggle, expiry,
  // extra links, revoke) stay available on the created link and via the "New link" button.
  const autoTried = useRef(false);
  useEffect(() => {
    if (links.data && links.data.length === 0 && !autoTried.current && !create.isPending) {
      autoTried.current = true;
      create.mutate();
    }
    // Only links.data (empty → auto-create once) should drive this; `create` is a fresh object every
    // render and would re-run the effect needlessly. The autoTried ref makes it fire exactly once.
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [links.data]);

  return (
    <div>
      <div className="flex items-center gap-2 text-sm font-medium mb-1">
        <Link2 className="w-4 h-4 text-muted" /> {t("downloads.share.linkSection")}
      </div>
      <p className="text-xs text-muted mb-2">{t("downloads.share.linkHint")}</p>

      <div className="space-y-2">
        {(links.data ?? []).map((l) => (
          <LinkRow key={l.id} link={l} onChanged={invalidate} />
        ))}
        {links.data && links.data.length === 0 && !creating && !create.isPending && (
          <p className="text-xs text-muted">{t("downloads.share.noLinks")}</p>
        )}
      </div>

      {creating ? (
        <div className="mt-2 rounded-lg border border-border p-3 space-y-3">
          <label className="flex items-center gap-2 text-sm cursor-pointer">
            <input
              type="checkbox"
              checked={allowDownload}
              onChange={(e) => setAllowDownload(e.target.checked)}
            />
            {t("downloads.share.allowDownload")}
          </label>
          <div className="flex items-center gap-2 text-sm">
            <span className="text-muted">{t("downloads.share.expiry")}:</span>
            {EXPIRY_DAYS.map((d) => (
              <button
                key={String(d)}
                onClick={() => setExpiryDays(d)}
                className={clsx(
                  "px-2 py-1 rounded-md border text-xs transition",
                  expiryDays === d
                    ? "border-accent bg-accent/10 text-accent"
                    : "border-border text-muted hover:text-fg",
                )}
              >
                {d === null
                  ? t("downloads.share.expiryNever")
                  : t("downloads.share.days", { n: d })}
              </button>
            ))}
          </div>
          <input
            type="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
            placeholder={t("downloads.share.password")}
            className={inputCls}
            autoComplete="new-password"
          />
          <div className="flex justify-end gap-2">
            <button
              onClick={() => setCreating(false)}
              className={clsx(btnCls, "text-muted hover:text-fg hover:bg-surface")}
            >
              {t("common.cancel")}
            </button>
            <button
              onClick={() => create.mutate()}
              disabled={create.isPending}
              className={clsx(btnCls, "bg-accent text-accent-fg hover:opacity-90")}
            >
              {t("downloads.share.createLink")}
            </button>
          </div>
        </div>
      ) : (
        <button
          onClick={() => setCreating(true)}
          className={clsx(
            btnCls,
            "mt-2 border border-border text-muted hover:text-fg hover:border-muted inline-flex items-center gap-1.5",
          )}
        >
          <Link2 className="w-4 h-4" /> {t("downloads.share.newLink")}
        </button>
      )}
    </div>
  );
}

export default function ShareDialog({ job, onClose }: { job: DownloadJob; onClose: () => void }) {
  const { t } = useTranslation();
  return (
    <Modal title={t("downloads.share.title")} onClose={onClose}>
      <div className="space-y-5">
        <UserShare job={job} />
        <div className="border-t border-border" />
        <LinkShare job={job} />
      </div>
    </Modal>
  );
}
