import React, { FormEvent, useEffect, useMemo, useState } from 'react';

import { saveCurrency } from '../service/user/user.service';
import { useAppStateContext } from '../context/user.data.context';
import { currencies } from '../utils';
import Banner from '../components/widgets/Banner';
import Button from '../components/widgets/Button';
import ErrorWrapper from '../components/alert/ErrorWrapper';
import SelectInput from '../components/widgets/SelectInput';

type Option = { label: string; value: string };

const Settings = (): JSX.Element => {
  const { token, user, fetchUser } = useAppStateContext();

  const [errors, setErrors] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [currencySaved, setCurrencySaved] = useState<boolean>(false);
  const [currency, setCurrency] = useState<Option | null>(null);

  const options: Option[] = useMemo(
    () =>
      (currencies || []).map((c: any) => ({
        label: c?.name ?? String(c?.cc ?? ''),
        value: c?.cc ?? '',
      })),
    []
  );

  const currentValue = user?.settings?.currency ?? 'USD';
  const isDirty = Boolean(currency?.value && currency?.value !== currentValue);

  useEffect(() => {
    if (!user && token) fetchUser();
  }, [user, token, fetchUser]);

  useEffect(() => {
    if (user && !currency) {
      const found = options.find(o => o.value === currentValue) ?? {
        label: 'US Dollar',
        value: 'USD',
      };
      setCurrency(found);
    }
  }, [user, currency, options, currentValue]);

  useEffect(() => {
    if (errors || currencySaved) {
      const timerId: ReturnType<typeof setTimeout> = setTimeout(() => {
        setErrors(null);
        setCurrencySaved(false);
      }, 4000);
      return () => clearTimeout(timerId);
    }
  }, [errors, currencySaved]);

  const handleSaveCurrency = async (
    e: FormEvent<HTMLFormElement>
  ): Promise<void> => {
    e.preventDefault();
    try {
      if (!currency?.value) {
        setErrors('Currency is required');
        return;
      }
      if (!isDirty) return;

      setIsLoading(true);
      const response = await saveCurrency(currency.value);
      if (response?.success) {
        await fetchUser();
        setCurrencySaved(true);
      } else {
        setErrors(
          response?.message || 'Unable to save currency. Please try again.'
        );
      }
    } catch (error: any) {
      setErrors(error?.message || 'Something went wrong. Please try again.');
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="w-full h-full p-6 md:p-10 bg-white">
      <main className="mx-auto w-full max-w-2xl">
        <header className="mb-8">
          <h1 className="text-xl font-medium text-gray-900">
            Currency Settings
          </h1>
          <p className="mt-1 text-sm text-gray-500">
            Choose the currency used for prices and reports across your
            workspace.
          </p>
        </header>

        <form onSubmit={handleSaveCurrency} className="space-y-6">
          <Banner
            type="success"
            open={currencySaved}
            setOpen={setCurrencySaved}
          >
            Currency successfully saved
          </Banner>

          <div className="rounded-lg border border-gray-200 bg-white p-6">
            <label
              htmlFor="currency"
              className="block text-sm font-medium text-gray-900 mb-3"
            >
              Default Currency
            </label>

            <div className="flex flex-col sm:flex-row gap-4">
              <div className="flex-1">
                <SelectInput
                  id="currency"
                  name="currency"
                  onChange={(e: any) => {
                    const label = e.target.value as string;
                    const found = options.find(o => o.label === label) || null;
                    setCurrency(found);
                  }}
                  options={options.map(o => o.label)}
                  value={currency ? currency.label : ''}
                />
              </div>

              <Button
                type="submit"
                isLoading={isLoading}
                disabled={isLoading || !isDirty || !currency?.value}
                className="whitespace-nowrap rounded-md bg-gray-900 px-5 py-2 text-sm font-medium text-white transition-colors hover:bg-gray-800 disabled:cursor-not-allowed disabled:opacity-50"
              >
                Save Changes
              </Button>
            </div>

            <div className="mt-4 flex items-center text-sm text-gray-500">
              <span>
                Current:{' '}
                <strong className="font-medium text-gray-900">
                  {currentValue}
                </strong>
              </span>
              {currency?.value && isDirty && (
                <>
                  <span className="mx-2 text-gray-300">→</span>
                  <span>
                    New:{' '}
                    <strong className="font-medium text-gray-900">
                      {currency.value}
                    </strong>
                  </span>
                </>
              )}
            </div>

            {errors && (
              <div className="mt-4">
                <ErrorWrapper error={errors} />
              </div>
            )}
          </div>

          <div className="flex items-start gap-3 text-sm text-gray-500">
            <svg
              viewBox="0 0 24 24"
              className="mt-0.5 h-4 w-4 shrink-0 text-gray-400"
              fill="currentColor"
              aria-hidden="true"
            >
              <path d="M12 2a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2Zm1 15h-2v-2h2Zm0-4h-2V7h2Z" />
            </svg>
            <p>
              You can change this at any time. Changes apply to new reports and
              UI labels immediately.
            </p>
          </div>
        </form>
      </main>
    </div>
  );
};

export default Settings;
