<script>
  import { createEventDispatcher, onMount } from "svelte";
  import api from "$/client/api.js";
  import { stripe_public, base_host } from "$/client/config.js";
  import Spinner from "$/client/components/Spinner.svelte";
  import { fade } from "svelte/transition";
  import { inject_remote } from "$/client/components/Source.svelte";

  export let appearance = {
    theme: 'flat',
    variables: {
      borderRadius: "5px",  // hate this
    }
  };

  const dispatch = createEventDispatcher();
  let state = "loading"; // loading, ready,
  let stripe;
  let elements;
  let error_message = "Please correct the form errors.";

  const initialize_stripe = async (data) => {
    await inject_remote(document, "https://js.stripe.com/v3/", () => {
      stripe = Stripe(stripe_public.client_id);
    });

    // initializing stripe
    const { clientSecret } = data;

    elements = stripe.elements({ appearance, clientSecret });

    const paymentElement = elements.create("payment");
    paymentElement.mount("#payment-element");
  }

  const configure_payment = async () => {
    // need to setup stripe first
    const [status, data] = await api.post("/api/payments/stripe");

    if(status === 200) {
      await initialize_stripe(data);
      state = "ready";
    } else {
      state = "error";
      dispatch("error", data);
    }
  }

  const handle_error = (error) => {
    state = "error";

    if (error.type === "card_error" || error.type === "validation_error") {
      // can't dispatch error here because stripe handles these?
      console.log("Stripe error", error);
      error_message = error.message || "Please correct the form errors.";
    } else {
      dispatch("error", error);
    }
  }


  const handle_submit = async () => {
    state = "submit";
    dispatch("click");

    const { error } = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: `${base_host}/api/payments/stripe`,
      }
    });

    if(error) {
      handle_error(error);
    } else {
      state = "submit_done";
    }
  }

  onMount(configure_payment);
</script>

<style>
  #load-cover {
    min-height: 40ex;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  #load-cover > p {
    color: var(--value4);
  }

  #payment-form {
    background-color: var(--value9);
    color: var(--value0);
    padding: 0.5rem;
    border-radius: var(--border-radius);
  }

  #payment-form button#submit {
    color: var(--value9);
    background-color: var(--value0);
    margin-top: 0.5rem;
  }

  #stripe-notice {
    width: 100%;
    text-align: center;
    color: var(--value3);
    font-size: 0.8em;
  }

  error {
    max-width: 400px;
  }
</style>

<div>
  <form id="payment-form">
    <div class="stacked">
      <div id="load-cover" class="layer" class:top={ state === "loading"}>
        {#if state === "loading"}
          <p out:fade|local={{ delay: 1000}}>Preparing payment form...</p>
        {/if}
      </div>
      <div id="payment-element" class="layer">
        <!--Stripe.js injects the Payment Element-->
      </div>
    </div>
    <br>
    {#if state === "error"}
      <error in:fade|local={{ delay: 1000}}>
        { error_message }
      </error>
    {/if}
    <button disabled={ state === "submit" } id="submit" on:click|preventDefault={ handle_submit }>
      {#if state === "submit"}
        <Spinner size="24" color="#fff"/>
      {:else}
        Pay with Credit Card
      {/if}
    </button>
    <div id="stripe-notice">Credit cards securely processed by <a href="https://stripe.com">Stripe</a>.</div>
  </form>
</div>
