<script lang="ts">
  import { open as openDialog } from "@tauri-apps/plugin-dialog";
  import {
    AlertTriangle,
    Check,
    CircleDot,
    ExternalLink,
    FolderInput,
    FolderOpen,
    GitBranch,
    HardDrive,
    LoaderCircle,
    Lock,
    MapPin,
    Plus,
    RefreshCw,
    ShieldCheck,
    Trash2,
    Unlock,
    Wrench,
    X,
  } from "@lucide/svelte";
  import type { GitBranch as GitBranchInfo, GitWorktree } from "../types";
  import SelectMenu from "./SelectMenu.svelte";

  type CreateMode = "existing" | "new" | "detached";

  interface AddRequest {
    worktreePath: string;
    branch?: string;
    newBranch?: string;
    startPoint?: string;
    detached?: boolean;
    lock?: boolean;
  }

  interface Props {
    worktrees: GitWorktree[];
    branches: GitBranchInfo[];
    initialBranch?: string;
    isLoading: boolean;
    isBusy: boolean;
    error?: string;
    onRefresh: () => void | Promise<void>;
    onOpen: (worktree: GitWorktree) => void | Promise<void>;
    onAdd: (request: AddRequest) => boolean | Promise<boolean>;
    onRemove: (worktree: GitWorktree, force: boolean) => boolean | Promise<boolean>;
    onMove: (worktree: GitWorktree, destination: string) => void | Promise<void>;
    onLock: (worktree: GitWorktree, reason: string) => boolean | Promise<boolean>;
    onUnlock: (worktree: GitWorktree) => void | Promise<void>;
    onPrune: () => void | Promise<void>;
    onRepair: (worktree: GitWorktree, location: string) => void | Promise<void>;
    onClose: () => void;
  }

  let {
    worktrees = [],
    branches = [],
    initialBranch = "",
    isLoading = false,
    isBusy = false,
    error = "",
    onRefresh = () => {},
    onOpen = () => {},
    onAdd = () => false,
    onRemove = () => false,
    onMove = () => {},
    onLock = () => false,
    onUnlock = () => {},
    onPrune = () => {},
    onRepair = () => {},
    onClose = () => {},
  }: Props = $props();

  let createOpen = $state(false);
  let createMode = $state<CreateMode>("new");
  let selectedBranch = $state("");
  let newBranch = $state("");
  let startPoint = $state("HEAD");
  let destination = $state("");
  let lockAfterCreate = $state(false);
  let pendingRemoval = $state<GitWorktree | null>(null);
  let forceRemoval = $state(false);
  let pendingLock = $state<GitWorktree | null>(null);
  let lockReason = $state("");
  let initialized = false;

  $effect(() => {
    if (initialized) return;
    createOpen = initialBranch.length > 0;
    createMode = initialBranch ? "existing" : "new";
    selectedBranch = initialBranch;
    initialized = true;
  });

  let localBranches = $derived(branches.filter((branch) => !branch.remote));
  let prunableCount = $derived(worktrees.filter((worktree) => worktree.prunable).length);
  let linkedCount = $derived(Math.max(0, worktrees.length - 1));
  let checkedOutBranches = $derived(new Set(worktrees.map((worktree) => worktree.branch).filter((branch): branch is string => Boolean(branch))));

  function displayName(worktree: GitWorktree): string {
    return worktree.branch || (worktree.detached ? `Detached at ${worktree.short_head || "HEAD"}` : "Bare worktree");
  }

  function pathName(path: string): string {
    return path.split(/[\\/]/).filter(Boolean).pop() || path;
  }

  function branchAvailable(branch: string): boolean {
    return !checkedOutBranches.has(branch);
  }

  function joinPath(parent: string, name: string): string {
    const separator = parent.includes("\\") ? "\\" : "/";
    return `${parent.replace(/[\\/]+$/, "")}${separator}${name}`;
  }

  async function chooseDestination(current = "") {
    const selected = await openDialog({
      title: current ? "Choose new worktree location" : "Choose worktree folder",
      directory: true,
      multiple: false,
      defaultPath: current || undefined,
    });
    if (typeof selected === "string") destination = selected;
  }

  async function submitCreate(event: SubmitEvent) {
    event.preventDefault();
    if (!destination.trim()) return;
    const request: AddRequest = {
      worktreePath: destination.trim(),
      lock: lockAfterCreate,
    };
    if (createMode === "existing") request.branch = selectedBranch;
    if (createMode === "new") {
      request.newBranch = newBranch.trim();
      request.startPoint = startPoint.trim() || "HEAD";
    }
    if (createMode === "detached") {
      request.detached = true;
      request.startPoint = startPoint.trim() || "HEAD";
    }
    if (await onAdd(request)) {
      createOpen = false;
      destination = "";
      newBranch = "";
    }
  }

  async function chooseMoveDestination(worktree: GitWorktree) {
    const selected = await openDialog({
      title: `Choose parent folder for ${displayName(worktree)}`,
      directory: true,
      multiple: false,
      defaultPath: worktree.path,
    });
    if (typeof selected === "string") {
      const target = joinPath(selected, pathName(worktree.path));
      if (target !== worktree.path) await onMove(worktree, target);
    }
  }

  async function chooseRepairLocation(worktree: GitWorktree) {
    const selected = await openDialog({
      title: `Locate ${displayName(worktree)}`,
      directory: true,
      multiple: false,
    });
    if (typeof selected === "string") await onRepair(worktree, selected);
  }

  function requestRemoval(worktree: GitWorktree) {
    pendingRemoval = worktree;
    forceRemoval = false;
  }

  async function confirmRemoval() {
    if (!pendingRemoval) return;
    if (await onRemove(pendingRemoval, forceRemoval)) {
      pendingRemoval = null;
      forceRemoval = false;
    }
  }

  function requestLock(worktree: GitWorktree) {
    pendingLock = worktree;
    lockReason = "";
  }

  async function confirmLock() {
    if (!pendingLock) return;
    if (await onLock(pendingLock, lockReason)) {
      pendingLock = null;
      lockReason = "";
    }
  }
</script>

<div class="dialog-backdrop" role="presentation">
  <div class="dialog worktree-dialog" role="dialog" aria-modal="true" aria-labelledby="worktree-dialog-title">
    <header class="dialog-header worktree-dialog-header">
      <div class="worktree-dialog-heading">
        <span class="worktree-dialog-mark" aria-hidden="true"><HardDrive size={18} /></span>
        <div>
          <span class="eyebrow">Parallel workspaces</span>
          <p class="dialog-title" id="worktree-dialog-title">Worktrees</p>
        </div>
      </div>
      <div class="dialog-header-actions">
        <button class="btn-sm" type="button" onclick={onRefresh} disabled={isBusy || isLoading} title="Refresh worktrees">
          <RefreshCw class={isLoading ? "spin" : undefined} size={15} aria-hidden="true" />
          Refresh
        </button>
        <button class="btn-sm dialog-close" type="button" onclick={onClose} disabled={isBusy} aria-label="Close">
          <X size={16} aria-hidden="true" />
        </button>
      </div>
    </header>

    <div class="worktree-summary">
      <div><strong>{linkedCount}</strong><span>linked worktrees</span></div>
      <div><strong>{worktrees.filter((worktree) => !worktree.clean).length}</strong><span>with changes</span></div>
      <div class:attention={prunableCount > 0}><strong>{prunableCount}</strong><span>stale entries</span></div>
      <button class="btn-primary" type="button" onclick={() => { createOpen = !createOpen; }} disabled={isBusy}>
        <Plus size={15} aria-hidden="true" />
        New worktree
      </button>
    </div>

    {#if error}
      <div class="worktree-error" role="alert"><AlertTriangle size={15} aria-hidden="true" />{error}</div>
    {/if}

    <div class="worktree-content">
      {#if createOpen}
        <form class="worktree-create-card" onsubmit={submitCreate}>
          <header>
            <div>
              <span class="eyebrow">Create</span>
              <h3>Choose what this workspace should track</h3>
            </div>
            <button class="btn-sm dialog-close" type="button" onclick={() => { createOpen = false; }} disabled={isBusy} aria-label="Close create form">
              <X size={15} aria-hidden="true" />
            </button>
          </header>

          <div class="worktree-mode-tabs" role="tablist" aria-label="Worktree type">
            <button class:active={createMode === "existing"} type="button" role="tab" aria-selected={createMode === "existing"} onclick={() => { createMode = "existing"; }}>
              <GitBranch size={14} aria-hidden="true" />Existing branch
            </button>
            <button class:active={createMode === "new"} type="button" role="tab" aria-selected={createMode === "new"} onclick={() => { createMode = "new"; }}>
              <Plus size={14} aria-hidden="true" />New branch
            </button>
            <button class:active={createMode === "detached"} type="button" role="tab" aria-selected={createMode === "detached"} onclick={() => { createMode = "detached"; }}>
              <CircleDot size={14} aria-hidden="true" />Detached
            </button>
          </div>

          <div class="worktree-create-fields">
            {#if createMode === "existing"}
              <label>
                <span>Branch</span>
                <SelectMenu
                  value={selectedBranch}
                  placeholder="Select a local branch"
                  options={localBranches.map((branch) => ({
                    value: branch.name,
                    label: `${branch.name}${!branchAvailable(branch.name) ? " (already checked out)" : ""}`,
                    disabled: !branchAvailable(branch.name),
                  }))}
                  disabled={isBusy}
                  onChange={(value) => { selectedBranch = value; }}
                />
              </label>
            {:else if createMode === "new"}
              <label>
                <span>New branch name</span>
                <input bind:value={newBranch} disabled={isBusy} autocomplete="off" spellcheck="false" placeholder="feature/my-change" />
              </label>
              <label>
                <span>Start point</span>
                <input bind:value={startPoint} disabled={isBusy} autocomplete="off" spellcheck="false" placeholder="HEAD, branch or commit" />
              </label>
            {:else}
              <label>
                <span>Commit or ref</span>
                <input bind:value={startPoint} disabled={isBusy} autocomplete="off" spellcheck="false" placeholder="HEAD" />
              </label>
            {/if}

            <label class="worktree-path-field">
              <span>Folder</span>
              <div>
                <input bind:value={destination} disabled={isBusy} autocomplete="off" spellcheck="false" placeholder="Choose an empty folder" />
                <button class="btn-secondary" type="button" onclick={() => chooseDestination()} disabled={isBusy}>
                  <FolderOpen size={15} aria-hidden="true" />Browse
                </button>
              </div>
            </label>
          </div>

          <footer>
            <label class="worktree-check">
              <input type="checkbox" bind:checked={lockAfterCreate} disabled={isBusy} />
              <span><strong>Lock after creation</strong><small>Protects removable or temporary locations from pruning.</small></span>
            </label>
            <button
              class="btn-primary"
              type="submit"
              disabled={isBusy || !destination.trim() || (createMode === "existing" && (!selectedBranch || !branchAvailable(selectedBranch))) || (createMode === "new" && !newBranch.trim())}
            >
              {#if isBusy}<LoaderCircle class="spin" size={15} aria-hidden="true" />{:else}<Plus size={15} aria-hidden="true" />{/if}
              Create worktree
            </button>
          </footer>
        </form>
      {/if}

      {#if isLoading && worktrees.length === 0}
        <div class="worktree-loading"><LoaderCircle class="spin" size={22} aria-hidden="true" /><span>Reading worktrees…</span></div>
      {:else if worktrees.length === 0}
        <div class="worktree-empty"><HardDrive size={24} aria-hidden="true" /><strong>No worktrees found</strong><span>Create one to work on another branch without switching this workspace.</span></div>
      {:else}
        <div class="worktree-list">
          {#each worktrees as worktree (worktree.path)}
            <article class:current={worktree.is_current} class:stale={worktree.prunable || worktree.missing} class="worktree-card">
              <div class="worktree-rail" aria-hidden="true">
                <span></span>
                {#if !worktree.is_main}<i></i>{/if}
              </div>
              <div class="worktree-card-main">
                <header>
                  <div class="worktree-name">
                    <GitBranch size={16} aria-hidden="true" />
                    <div>
                      <strong>{displayName(worktree)}</strong>
                      <span>{pathName(worktree.path)}</span>
                    </div>
                  </div>
                  <div class="worktree-badges">
                    {#if worktree.is_main}<span>Main</span>{/if}
                    {#if worktree.is_current}<span class="active">Open</span>{/if}
                    {#if worktree.detached}<span>Detached</span>{/if}
                    {#if worktree.locked}<span class="locked"><Lock size={10} aria-hidden="true" />Locked</span>{/if}
                    {#if worktree.prunable || worktree.missing}<span class="danger">Stale</span>{/if}
                  </div>
                </header>

                <div class="worktree-path" title={worktree.path}><MapPin size={13} aria-hidden="true" /><code>{worktree.path}</code></div>

                <div class="worktree-meta">
                  <span class:dirty={!worktree.clean}>
                    {#if worktree.clean}<Check size={12} aria-hidden="true" />Clean{:else}<CircleDot size={12} aria-hidden="true" />{worktree.changed_files} changed{/if}
                  </span>
                  {#if worktree.short_head}<span><code>{worktree.short_head}</code></span>{/if}
                  {#if worktree.lock_reason}<span><Lock size={12} aria-hidden="true" />{worktree.lock_reason}</span>{/if}
                  {#if worktree.prune_reason}<span class="danger"><AlertTriangle size={12} aria-hidden="true" />{worktree.prune_reason}</span>{/if}
                </div>

                <footer>
                  <button class="btn-secondary" type="button" onclick={() => onOpen(worktree)} disabled={isBusy || worktree.missing || worktree.bare}>
                    <ExternalLink size={14} aria-hidden="true" />{worktree.is_current ? "Refresh tab" : "Open tab"}
                  </button>
                  <div class="worktree-card-actions">
                    {#if worktree.prunable}
                      <button class="btn-sm" type="button" onclick={() => chooseRepairLocation(worktree)} disabled={isBusy} title="Locate and repair worktree">
                        <Wrench size={14} aria-hidden="true" />Repair
                      </button>
                    {/if}
                    {#if !worktree.is_main && !worktree.missing}
                      <button class="btn-sm" type="button" onclick={() => chooseMoveDestination(worktree)} disabled={isBusy || worktree.locked || worktree.is_current} title="Move worktree">
                        <FolderInput size={14} aria-hidden="true" />Move
                      </button>
                    {/if}
                    {#if worktree.locked}
                      <button class="btn-sm" type="button" onclick={() => onUnlock(worktree)} disabled={isBusy} title="Unlock worktree">
                        <Unlock size={14} aria-hidden="true" />Unlock
                      </button>
                    {:else if !worktree.is_main}
                      <button class="btn-sm" type="button" onclick={() => requestLock(worktree)} disabled={isBusy} title="Lock worktree">
                        <Lock size={14} aria-hidden="true" />Lock
                      </button>
                    {/if}
                    {#if !worktree.is_main}
                      <button class="btn-sm danger" type="button" onclick={() => requestRemoval(worktree)} disabled={isBusy || worktree.is_current || worktree.locked || worktree.missing} title={worktree.missing ? "Use Prune to remove stale metadata" : "Remove worktree"}>
                        <Trash2 size={14} aria-hidden="true" />Remove
                      </button>
                    {/if}
                  </div>
                </footer>
              </div>
            </article>
          {/each}
        </div>
      {/if}
    </div>

    <footer class="worktree-dialog-footer">
      <div><ShieldCheck size={14} aria-hidden="true" /><span>Dirty, active and locked worktrees are protected.</span></div>
      <button class="btn-secondary" type="button" onclick={onPrune} disabled={isBusy || prunableCount === 0}>
        <Wrench size={14} aria-hidden="true" />Prune {prunableCount || ""}
      </button>
    </footer>
  </div>
</div>

{#if pendingRemoval}
  <div class="dialog-backdrop worktree-nested-backdrop" role="presentation">
    <div class="dialog worktree-confirm-dialog" role="alertdialog" aria-modal="true" aria-labelledby="worktree-remove-title">
      <header class="dialog-header">
        <div>
          <span class="eyebrow">Remove worktree</span>
          <p class="dialog-title" id="worktree-remove-title">Remove {displayName(pendingRemoval)}?</p>
        </div>
      </header>
      <div class="worktree-confirm-body">
        <span class="discard-warning-icon" aria-hidden="true"><AlertTriangle size={21} /></span>
        <div>
          <p>This removes the worktree folder and its Git registration. The branch itself is kept.</p>
          <code>{pendingRemoval.path}</code>
          {#if !pendingRemoval.clean}
            <label class="worktree-check danger">
              <input type="checkbox" bind:checked={forceRemoval} disabled={isBusy} />
              <span><strong>Remove despite local changes</strong><small>{pendingRemoval.changed_files} changed files may be permanently deleted.</small></span>
            </label>
          {/if}
        </div>
      </div>
      <footer class="discard-confirm-actions">
        <button class="btn-secondary" type="button" onclick={() => { pendingRemoval = null; }} disabled={isBusy}>Cancel</button>
        <button class="btn-danger" type="button" onclick={confirmRemoval} disabled={isBusy || (!pendingRemoval.clean && !forceRemoval)}>
          <Trash2 size={15} aria-hidden="true" />Remove worktree
        </button>
      </footer>
    </div>
  </div>
{/if}

{#if pendingLock}
  <div class="dialog-backdrop worktree-nested-backdrop" role="presentation">
    <div class="dialog worktree-confirm-dialog" role="dialog" aria-modal="true" aria-labelledby="worktree-lock-title">
      <header class="dialog-header">
        <div>
          <span class="eyebrow">Protect worktree</span>
          <p class="dialog-title" id="worktree-lock-title">Lock {displayName(pendingLock)}</p>
        </div>
      </header>
      <div class="worktree-lock-body">
        <label>
          <span>Reason <small>optional</small></span>
          <input bind:value={lockReason} disabled={isBusy} autocomplete="off" placeholder="External drive, long-running work…" />
        </label>
      </div>
      <footer class="discard-confirm-actions">
        <button class="btn-secondary" type="button" onclick={() => { pendingLock = null; }} disabled={isBusy}>Cancel</button>
        <button class="btn-primary" type="button" onclick={confirmLock} disabled={isBusy}><Lock size={15} aria-hidden="true" />Lock</button>
      </footer>
    </div>
  </div>
{/if}
