<script lang="ts">
  import { untrack } from "svelte";
  import {
    AlertCircle,
    Download,
    Eye,
    EyeOff,
    Key,
    LoaderCircle,
    Lock,
    ShieldCheck,
    Upload,
    User,
    X,
  } from "@lucide/svelte";

  interface Props {
    action: "push" | "pull" | "fetch" | "clone" | "rename" | "delete";
    error: string;
    isBusy: boolean;
    initialUsername?: string;
    initialMode?: Mode;
    onSubmit: (username: string, password: string, save: boolean, mode: Mode) => void;
    onCancel: () => void;
  }

  let {
    action,
    error = "",
    isBusy = false,
    initialUsername = "",
    initialMode = "credentials",
    onSubmit,
    onCancel,
  }: Props = $props();

  type Mode = "credentials" | "token";

  let mode = $state<Mode>(untrack(() => initialMode));
  let username = $state(untrack(() => initialUsername === "oauth2" ? "" : initialUsername));
  let password = $state("");
  let showPassword = $state(false);
  let saveSession = $state(true);

  let canSubmit = $derived(
    !isBusy &&
    password.trim().length > 0 &&
    username.trim().length > 0,
  );
  let actionLabel = $derived(action === "push" ? "Push" : action === "fetch" ? "Fetch" : action === "clone" ? "Clone" : action === "rename" ? "Rename" : action === "delete" ? "Delete" : "Pull");
  let actionTitle = $derived(
    action === "push"
      ? "Authenticate push"
      : action === "rename"
        ? "Authenticate remote rename"
        : action === "delete"
          ? "Authenticate remote deletion"
          : action === "fetch"
            ? "Authenticate fetch"
            : action === "clone"
              ? "Authenticate clone"
              : "Authenticate pull",
  );
  let actionHint = $derived(action === "push" || action === "rename" || action === "delete"
    ? "The remote needs write access. Use a password or a token with the appropriate repository permissions."
    : action === "clone"
      ? "The repository needs access before it can be cloned. Use your Git credentials or a personal access token."
      : "The remote needs access to the repository. Use your Git credentials or a personal access token.");

  function handleSubmit(e: SubmitEvent) {
    e.preventDefault();
    if (!canSubmit) return;
    onSubmit(username.trim(), password, saveSession, mode);
  }
</script>

<div
  class="dialog-backdrop"
  role="presentation"
>
  <div class="cred-card" role="dialog" aria-modal="true" aria-label="Git credentials" tabindex="-1">
    <div class="cred-hero">
      <div class="cred-hero-top">
        <div class="cred-hero-icon">
          {#if action === "push" || action === "rename" || action === "delete"}
            <Upload size={27} aria-hidden="true" />
          {:else}
            <Download size={27} aria-hidden="true" />
          {/if}
        </div>
        <div class="cred-hero-text">
          <p class="cred-hero-label">{actionLabel} Remote</p>
          <h2 class="cred-hero-title">{actionTitle}</h2>
        </div>
        <button class="cred-close" type="button" onclick={onCancel} title="Cancel" aria-label="Cancel">
          <X size={16} aria-hidden="true" />
        </button>
      </div>

      <p class="cred-hero-copy">{actionHint}</p>

      <div class="cred-security-note">
        <ShieldCheck size={14} aria-hidden="true" />
        <span>When saved, the credentials are stored encrypted in the operating system's keychain — never in plain text.</span>
      </div>
    </div>

    <form class="cred-body" onsubmit={handleSubmit}>
      <div class="cred-segment" role="group" aria-label="Authentication method">
        <button
          type="button"
          class="cred-seg-btn"
          class:active={mode === "credentials"}
          onclick={() => { mode = "credentials"; }}
          aria-pressed={mode === "credentials"}
        >
          <User size={13} aria-hidden="true" />
          Username + password
        </button>
        <button
          type="button"
          class="cred-seg-btn"
          class:active={mode === "token"}
          onclick={() => { mode = "token"; }}
          aria-pressed={mode === "token"}
        >
          <Key size={13} aria-hidden="true" />
          Access token
        </button>
      </div>

      <div class="cred-fields">
        <div class="cred-field">
          <label class="cred-field-label" for="cred-username">Username</label>
          <div class="cred-input">
            <User size={15} class="cred-field-icon" aria-hidden="true" />
            <input
              id="cred-username"
              type="text"
              bind:value={username}
              placeholder="Your account username"
              autocomplete="username"
              disabled={isBusy}
            />
          </div>
        </div>

        <div class="cred-field">
          <label class="cred-field-label" for="cred-password">
            {mode === "token" ? "Token" : "Password"}
          </label>
          <div class="cred-input">
            <Lock size={15} class="cred-field-icon" aria-hidden="true" />
            <input
              id="cred-password"
              type={showPassword ? "text" : "password"}
              bind:value={password}
              placeholder={mode === "token"
                ? "ghp_... or another access token"
                : "Password or personal access token"}
              autocomplete="current-password"
              disabled={isBusy}
            />
            <button
              type="button"
              class="cred-reveal"
              onclick={() => { showPassword = !showPassword; }}
              tabindex="-1"
              aria-label={showPassword ? "Hide" : "Show"}
            >
              {#if showPassword}
                <EyeOff size={14} aria-hidden="true" />
              {:else}
                <Eye size={14} aria-hidden="true" />
              {/if}
            </button>
          </div>
        </div>
      </div>

      {#if mode === "token"}
        <div class="cred-token-hint">
          <Key size={13} aria-hidden="true" />
          <span>Use your normal account username. The access token is sent as the password, as required by Gitea and most Git providers.</span>
        </div>
      {/if}

      {#if error}
        <div class="cred-error" role="alert">
          <AlertCircle size={14} aria-hidden="true" />
          <span>{error}</span>
        </div>
      {/if}

      <div class="cred-footer">
        <label class="cred-save">
          <input type="checkbox" bind:checked={saveSession} disabled={isBusy} />
          <span>Save in keychain</span>
        </label>

        <div class="cred-btns">
          <button type="button" class="cred-cancel" onclick={onCancel} disabled={isBusy}>
            Cancel
          </button>
          <button class="cred-submit" type="submit" disabled={!canSubmit}>
            {#if isBusy}
              <LoaderCircle class="spin" size={15} aria-hidden="true" />
            {:else if action === "push"}
              <Upload size={15} aria-hidden="true" />
            {:else}
              <Download size={15} aria-hidden="true" />
            {/if}
            {actionLabel}
          </button>
        </div>
      </div>
    </form>
  </div>
</div>
