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

  interface Props {
    action: "push" | "pull" | "fetch";
    error: string;
    isBusy: boolean;
    onSubmit: (username: string, password: string, save: boolean, expiresAt: string | null) => void;
    onCancel: () => void;
  }

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

  type Mode = "credentials" | "token";

  let mode = $state<Mode>("credentials");
  let username = $state("");
  let password = $state("");
  let showPassword = $state(false);
  let saveSession = $state(false);
  let expiresAt = $state("");

  let canSubmit = $derived(
    !isBusy &&
    password.trim().length > 0 &&
    (mode === "token" || username.trim().length > 0),
  );
  let actionLabel = $derived(action === "push" ? "Push" : action === "fetch" ? "Fetch" : "Pull");
  let actionTitle = $derived(
    action === "push" ? "Authenticate push" : action === "fetch" ? "Authenticate fetch" : "Authenticate pull",
  );
  let actionHint = $derived(action === "push"
    ? "The remote needs write access. Use a password or a token with the appropriate repository permissions."
    : "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(
      mode === "token" ? "oauth2" : username,
      password,
      saveSession,
      saveSession && expiresAt ? expiresAt : null,
    );
  }
</script>

<div
  class="dialog-backdrop"
  role="presentation"
  onclick={(e) => { if (e.target === e.currentTarget) onCancel(); }}
>
  <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"}
            <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 token is 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" />
          Token
        </button>
      </div>

      <div class="cred-fields">
        {#if mode === "credentials"}
          <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="e.g. my-github-username"
                autocomplete="username"
                disabled={isBusy}
              />
            </div>
          </div>
        {/if}

        <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>Username is automatically set to <code>oauth2</code>. This works with GitHub, GitLab, and Bitbucket.</span>
        </div>
      {/if}

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

      {#if saveSession}
        <div class="cred-expiry">
          <label class="cred-field-label" for="cred-expiry">Expiration date (optional)</label>
          <input
            id="cred-expiry"
            type="date"
            bind:value={expiresAt}
            disabled={isBusy}
          />
          <span class="cred-expiry-hint">After this date you'll automatically be asked to log in again.</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>
