<script lang="ts">
  import cx from "classnames"
  import {LOCALE, always, call, removeAt, replaceAt, sleep} from "@welshman/lib"
  import {WalletType, displayRelayUrl, isNWCWallet, fromMsats} from "@welshman/util"
  import {session, pubkey, profilesByPubkey} from "@welshman/app"
  import DownloadMinimalistic from "@assets/icons/download-minimalistic.svg?dataurl"
  import UploadMinimalistic from "@assets/icons/upload-minimalistic.svg?dataurl"
  import Bolt from "@assets/icons/bolt.svg?dataurl"
  import AddCircle from "@assets/icons/add-circle.svg?dataurl"
  import TrashBin2 from "@assets/icons/trash-bin-2.svg?dataurl"
  import {preventDefault} from "@lib/html"
  import Icon from "@lib/components/Icon.svelte"
  import Button from "@lib/components/Button.svelte"
  import Spinner from "@lib/components/Spinner.svelte"
  import WalletPay from "@app/components/WalletPay.svelte"
  import WalletReceive from "@app/components/WalletReceive.svelte"
  import WalletConnect from "@app/components/WalletConnect.svelte"
  import WalletDisconnect from "@app/components/WalletDisconnect.svelte"
  import WalletUpdateReceivingAddress from "@app/components/WalletUpdateReceivingAddress.svelte"
  import {pushModal} from "@app/modal"
  import {getNwcClient, getWebLn} from "@app/lightning"
  import {zapAmounts} from "@app/settings"
  import {pushToast} from "@app/toast"
  import Wallet2 from "@assets/icons/wallet.svg?dataurl"
  import CheckCircle from "@assets/icons/check-circle.svg?dataurl"
  import CloseCircle from "@assets/icons/close-circle.svg?dataurl"
  import InfoCircle from "@assets/icons/info-circle.svg?dataurl"

  const connect = () => pushModal(WalletConnect)

  const disconnect = () => pushModal(WalletDisconnect)

  const updateReceivingAddress = () => pushModal(WalletUpdateReceivingAddress)

  const profile = $derived($profilesByPubkey.get($pubkey || ""))
  const profileLightningAddress = $derived(profile?.lud16)
  const walletLud16 = $derived(
    $session?.wallet && isNWCWallet($session.wallet) ? $session.wallet.info.lud16 : undefined,
  )

  const pay = () => pushModal(WalletPay)

  const receive = () => {
    if ($session?.wallet) {
      pushModal(WalletReceive)
    } else {
      pushModal(WalletConnect)
    }
  }

  let walletStatus = $state("checking")

  const isWalletAvailable = $derived(Boolean($session?.wallet) && walletStatus === "connected")
  const statusClass = $derived(
    cx("flex items-center gap-2 text-sm", {
      "text-success": walletStatus === "connected",
      "text-warning": walletStatus === "unavailable",
    }),
  )
  const connectionVerb = $derived(walletStatus === "connected" ? "Connected to" : "Configured for")

  const startWalletStatusCheck = async (wallet = $session?.wallet) => {
    walletStatus = "checking"

    if (wallet) {
      const promise =
        wallet.type === WalletType.NWC
          ? getNwcClient().getInfo()
          : call(async () => {
              const client = getWebLn()

              await client.enable()

              return client.getInfo()
            })

      walletStatus = await Promise.race([
        promise.then(always("connected")).catch(always("unavailable")),
        sleep(5000).then(always("unavailable")),
      ])
    }
  }

  $effect(() => {
    startWalletStatusCheck($session?.wallet)
  })

  const resetZapAmounts = () => {
    zapAmountDraft = [...zapAmounts.get()]
  }

  const addZapAmount = () => {
    zapAmountDraft = [...zapAmountDraft, zapAmountDraft.at(-1) || 21]
  }

  const removeZapAmount = (index: number) => {
    if (zapAmountDraft.length > 1) {
      zapAmountDraft = removeAt(index, zapAmountDraft)
    }
  }

  const onZapAmountInput = (e: Event) => {
    const target = e.currentTarget as HTMLInputElement
    const index = Number(target.dataset.index)

    zapAmountDraft = replaceAt(index, Number(target.value), zapAmountDraft)
  }

  const onZapAmountsSubmit = preventDefault(() => {
    zapAmountsLoading = true

    try {
      const amounts = zapAmountDraft.filter(amount => amount > 0)

      if (amounts.length === 0) {
        return pushToast({
          theme: "error",
          message: "Add at least one zap amount greater than zero.",
        })
      }

      zapAmounts.set(amounts)
      zapAmountDraft = [...amounts]

      pushToast({message: "Your zap amounts have been saved!"})
    } finally {
      zapAmountsLoading = false
    }
  })

  let zapAmountDraft = $state([...zapAmounts.get()])
  let zapAmountsLoading = $state(false)
</script>

<div class="content column gap-4">
  <div class="card2 bg-alt flex flex-col gap-6 shadow-md">
    <div class="flex items-center justify-between">
      <strong class="flex items-center gap-3 text-lg">
        <Icon icon={Wallet2} />
        Your Wallet
      </strong>
      {#if $session?.wallet}
        <div class={statusClass}>
          {#if walletStatus === "checking"}
            <span class="loading loading-spinner loading-xs"></span>
            Checking
          {:else if walletStatus === "connected"}
            <Icon icon={CheckCircle} size={4} />
            Connected
          {:else}
            <Icon icon={InfoCircle} size={4} />
            Unavailable
          {/if}
        </div>
      {:else}
        <Button class="btn btn-primary btn-sm" onclick={connect}>
          <Icon icon={AddCircle} />
          Connect Wallet
        </Button>
      {/if}
    </div>
    <div class="col-4">
      {#if $session?.wallet}
        {#if $session.wallet.type === "webln"}
          {@const {node, version} = $session.wallet.info}
          <div class="flex flex-col justify-between gap-2 lg:flex-row">
            <p>
              {connectionVerb} <strong>{node?.alias || version || "unknown wallet"}</strong>
              via <strong>{$session.wallet.type}</strong>
            </p>
            <p class="flex gap-2 whitespace-nowrap">
              {#if walletStatus === "connected"}
                Balance:
                {#await getWebLn()
                  ?.enable()
                  .then(() => getWebLn().getBalance())}
                  <span class="loading loading-spinner loading-sm"></span>
                {:then res}
                  {new Intl.NumberFormat(LOCALE).format(res?.balance || 0)}
                {:catch}
                  [unknown]
                {/await}
                sats
              {:else if walletStatus === "checking"}
                Balance:
                <span class="loading loading-spinner loading-sm"></span>
              {:else}
                Balance unavailable
              {/if}
            </p>
          </div>
        {:else if $session.wallet.type === "nwc"}
          {@const {lud16, relayUrl} = $session.wallet.info}
          <div class="flex flex-col justify-between gap-2 lg:flex-row">
            <p>
              {connectionVerb} <strong>{lud16}</strong> via
              <strong>{displayRelayUrl(relayUrl)}</strong>
            </p>
            <p class="flex gap-2 whitespace-nowrap">
              {#if walletStatus === "connected"}
                Balance:
                {#await getNwcClient().getBalance()}
                  <span class="loading loading-spinner loading-sm"></span>
                {:then res}
                  {new Intl.NumberFormat(LOCALE).format(fromMsats(res?.balance || 0))}
                {:catch}
                  [unknown]
                {/await}
                sats
              {:else if walletStatus === "checking"}
                Balance:
                <span class="loading loading-spinner loading-sm"></span>
              {:else}
                Balance unavailable
              {/if}
            </p>
          </div>
        {/if}
        <div class="flex flex-col gap-4 lg:flex-row lg:justify-between">
          <Button class="btn btn-neutral btn-sm" onclick={disconnect}>
            <Icon icon={CloseCircle} />
            Disconnect Wallet
          </Button>
          <div class="flex w-full gap-4 lg:w-auto">
            <Button
              class="btn btn-primary btn-sm flex-1 justify-center lg:flex-none"
              onclick={pay}
              disabled={!isWalletAvailable}>
              <Icon icon={UploadMinimalistic} />
              Send
            </Button>
            <Button
              class="btn btn-secondary btn-sm flex-1 justify-center lg:flex-none"
              onclick={receive}
              disabled={!isWalletAvailable}>
              <Icon icon={DownloadMinimalistic} />
              Receive
            </Button>
          </div>
        </div>
      {:else}
        <p class="py-12 text-center opacity-75">No wallet connected</p>
      {/if}
    </div>
  </div>
  <div class="card2 bg-alt flex flex-col shadow-md gap-6">
    <strong>Lightning Address</strong>
    <div class="flex justify-between items-center gap-2">
      <span class={profileLightningAddress ? "" : "text-warning"}>
        {profileLightningAddress ? profileLightningAddress : "Not set"}
      </span>
      <Button class="btn btn-neutral btn-xs ml-3" onclick={updateReceivingAddress}>Update</Button>
    </div>
    {#if profileLightningAddress && walletLud16 && profile?.lud16 !== walletLud16}
      <div class="card2 bg-alt flex items-center gap-2 text-xs">
        <Icon icon={InfoCircle} size={4} />
        Your profile has a different lightning address than your connected wallet.
      </div>
    {/if}
  </div>
  <form class="card2 bg-alt flex flex-col gap-6 shadow-md" onsubmit={onZapAmountsSubmit}>
    <strong class="flex items-center gap-3 text-lg">
      <Icon icon={Bolt} />
      Zap Amounts
    </strong>
    <p class="text-sm opacity-75">Preset amounts shown when sending a zap.</p>
    <div class="flex flex-col gap-2">
      {#each zapAmountDraft as amount, index}
        <div class="flex items-center gap-2">
          <Button
            class="btn btn-ghost btn-sm"
            type="button"
            onclick={() => removeZapAmount(index)}
            disabled={zapAmountDraft.length === 1}>
            <Icon icon={TrashBin2} />
          </Button>
          <label class="input input-bordered flex grow items-center gap-2">
            <Icon icon={Bolt} />
            <input
              type="number"
              class="grow"
              min="1"
              data-index={index}
              value={amount}
              oninput={onZapAmountInput} />
          </label>
        </div>
      {/each}
      <Button class="btn btn-link w-fit px-0" type="button" onclick={addZapAmount}>
        <Icon icon={AddCircle} size={5} />
        Add amount
      </Button>
    </div>
    <div class="flex flex-row items-center justify-between gap-4">
      <Button
        class="btn btn-neutral"
        type="button"
        onclick={resetZapAmounts}
        disabled={zapAmountsLoading}>
        Discard Changes
      </Button>
      <Button type="submit" class="btn btn-primary" disabled={zapAmountsLoading}>
        <Spinner loading={zapAmountsLoading}>Save Changes</Spinner>
      </Button>
    </div>
  </form>
</div>
