import { AmountString, Amounts, CurrencySpecification, TalerCorebankApi, TalerError, assertUnreachable } from "@gnu-taler/taler-util";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { format, getDate, getHours, getMonth, getYear, setDate, setHours, setMonth, setYear, sub } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
import { Transactions } from "../../components/Transactions/index.js";
import { useBankCoreApiContext } from "../../context/config.js";
import { useConversionInfo, useLastMonitorInfo } from "../../hooks/circuit.js";
import { RenderAmount } from "../PaytoWireTransferForm.js";
import { WireTransfer } from "../WireTransfer.js";
import { AccountList } from "./AccountList.js";


/**
 * Query account information and show QR code if there is pending withdrawal
 */
interface Props {
  onRegister: () => void;

  onCreateAccount: () => void;
  onShowAccountDetails: (aid: string) => void;
  onRemoveAccount: (aid: string) => void;
  onUpdateAccountPassword: (aid: string) => void;
  onShowCashoutForAccount: (aid: string) => void;
}
export function AdminHome({ onCreateAccount, onRegister, onRemoveAccount, onShowAccountDetails, onShowCashoutForAccount, onUpdateAccountPassword }: Props): VNode {
  return <Fragment>
    <Metrics />
    <WireTransfer onRegister={onRegister} />

    <Transactions account="admin" />
    <AccountList
      onCreateAccount={onCreateAccount}
      onRemoveAccount={onRemoveAccount}
      onShowCashoutForAccount={onShowCashoutForAccount}
      onShowAccountDetails={onShowAccountDetails}
      onUpdateAccountPassword={onUpdateAccountPassword}
    />

  </Fragment>
}

function getDateForTimeframe(which: number, timeframe: TalerCorebankApi.MonitorTimeframeParam): string {
  const time = Date.now()

  switch (timeframe) {
    case TalerCorebankApi.MonitorTimeframeParam.hour: return `${format(setHours(time, which), "HH")}hs`;
    case TalerCorebankApi.MonitorTimeframeParam.day: return format(setDate(time, which), "EEEE");
    case TalerCorebankApi.MonitorTimeframeParam.month: return format(setMonth(time, which), "MMMM");
    case TalerCorebankApi.MonitorTimeframeParam.year: return format(setYear(time, which), "yyyy");
    case TalerCorebankApi.MonitorTimeframeParam.decade: return format(setYear(time, which), "yyyy");
  }
  assertUnreachable(timeframe)
}

export function getTimeframesForDate(time: Date, timeframe: TalerCorebankApi.MonitorTimeframeParam): { current: number, previous: number } {
  switch (timeframe) {
    case TalerCorebankApi.MonitorTimeframeParam.hour: return {
      current: getHours(sub(time, { hours: 1 })),
      previous: getHours(sub(time, { hours: 2 }))
    }
    case TalerCorebankApi.MonitorTimeframeParam.day: return {
      current: getDate(sub(time, { days: 1 })),
      previous: getDate(sub(time, { days: 2 }))
    }
    case TalerCorebankApi.MonitorTimeframeParam.month: return {
      current: getMonth(sub(time, { months: 1 })),
      previous: getMonth(sub(time, { months: 2 }))
    }
    case TalerCorebankApi.MonitorTimeframeParam.year: return {
      current: getYear(sub(time, { years: 1 })),
      previous: getYear(sub(time, { years: 2 }))
    }
    case TalerCorebankApi.MonitorTimeframeParam.decade: return {
      current: getYear(sub(time, { years: 10 })),
      previous: getYear(sub(time, { years: 20 }))
    }
    default: assertUnreachable(timeframe)
  }
}


function Metrics(): VNode {
  const { i18n } = useTranslationContext()
  const [metricType, setMetricType] = useState<TalerCorebankApi.MonitorTimeframeParam>(TalerCorebankApi.MonitorTimeframeParam.hour);
  const { config } = useBankCoreApiContext();
  const respInfo = useConversionInfo()
  const params = getTimeframesForDate(new Date(), metricType)

  const resp = useLastMonitorInfo(params.current, params.previous, metricType);
  if (!resp) return <Fragment />;
  if (resp instanceof TalerError) {
    return <ErrorLoadingWithDebug error={resp} />
  }
  if (resp.current.type !== "ok" || resp.previous.type !== "ok") {
    return <Fragment />
  }
  const fiatSpec = respInfo && (!(respInfo instanceof TalerError)) ? respInfo.body.fiat_currency_specification : undefined
  return <Fragment>
    <div class="sm:hidden">
      <label for="tabs" class="sr-only"><i18n.Translate>Select a section</i18n.Translate></label>
      <select id="tabs" name="tabs" class="block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500" onChange={(e) => {
        // const op = e.currentTarget.value as typeof metricType
        setMetricType(e.currentTarget.value as any)
      }}>
        <option value={TalerCorebankApi.MonitorTimeframeParam.hour} selected={metricType == TalerCorebankApi.MonitorTimeframeParam.hour}><i18n.Translate>Last hour</i18n.Translate></option>
        <option value={TalerCorebankApi.MonitorTimeframeParam.day} selected={metricType == TalerCorebankApi.MonitorTimeframeParam.day}><i18n.Translate>Last day</i18n.Translate></option>
        <option value={TalerCorebankApi.MonitorTimeframeParam.month} selected={metricType == TalerCorebankApi.MonitorTimeframeParam.month}><i18n.Translate>Last month</i18n.Translate></option>
        <option value={TalerCorebankApi.MonitorTimeframeParam.year} selected={metricType == TalerCorebankApi.MonitorTimeframeParam.year}><i18n.Translate>Last year</i18n.Translate></option>
      </select>
    </div>
    <div class="hidden sm:block">
      <nav class="isolate flex divide-x divide-gray-200 rounded-lg shadow" aria-label="Tabs">
        <a href="#" onClick={(e) => { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.hour) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.hour} class="rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10" >
          <span><i18n.Translate>Last hour</i18n.Translate></span>
          <span aria-hidden="true" data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.hour} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span>
        </a>
        <a href="#" onClick={(e) => { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.day) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.day} aria-current="page" class="             text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10">
          <span><i18n.Translate>Last day</i18n.Translate></span>
          <span aria-hidden="true" data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.day} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span>
        </a>
        <a href="#" onClick={(e) => { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.month) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.month} class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10">
          <span><i18n.Translate>Last month</i18n.Translate></span>
          <span aria-hidden="true" data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.month} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span>
        </a>
        <a href="#" onClick={(e) => { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.year) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.year} class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10">
          <span><i18n.Translate>Last Year</i18n.Translate></span>
          <span aria-hidden="true" data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.year} class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"></span>
        </a>
      </nav>
    </div>

    <div class="w-full flex justify-between">
      <h1 class="text-base font-semibold leading-7 text-gray-900 mt-5">
        <i18n.Translate>Trading volume on {getDateForTimeframe(params.current, metricType)} compared to {getDateForTimeframe(params.previous, metricType)}</i18n.Translate>
      </h1>
    </div>
    <dl class="mt-5 grid grid-cols-1 md:grid-cols-2  divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0">

      {!fiatSpec || resp.current.body.type !== "with-conversions" || resp.previous.body.type !== "with-conversions" ? undefined :
        <Fragment>
          <div class="px-4 py-5 sm:p-6">
            <dt class="text-base font-normal text-gray-900">
              <i18n.Translate>Cashin</i18n.Translate>
            </dt>
            <MetricValue
              current={resp.current.body.cashinFiatVolume}
              previous={resp.previous.body.cashinFiatVolume}
              spec={fiatSpec}
            />
          </div>
          <div class="px-4 py-5 sm:p-6">
            <dt class="text-base font-normal text-gray-900">
              <i18n.Translate>Cashout</i18n.Translate>
            </dt>
            <MetricValue
              current={resp.current.body.cashoutFiatVolume}
              previous={resp.previous.body.cashoutFiatVolume}
              spec={fiatSpec}
            />
          </div>
        </Fragment>
      }
      <div class="px-4 py-5 sm:p-6">
        <dt class="text-base font-normal text-gray-900">
          <i18n.Translate>Payin</i18n.Translate>
        </dt>
        <MetricValue
          current={resp.current.body.talerInVolume}
          previous={resp.previous.body.talerInVolume}
          spec={config.currency_specification}
        />
      </div>
      <div class="px-4 py-5 sm:p-6">
        <dt class="text-base font-normal text-gray-900">
          <i18n.Translate>Payout</i18n.Translate>
        </dt>
        <MetricValue
          current={resp.current.body.talerOutVolume}
          previous={resp.previous.body.talerOutVolume}
          spec={config.currency_specification}
        />
      </div>
    </dl>
    <div class="flex justify-end mt-2">
      <a href="#/download-stats" 
              class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
              ><i18n.Translate>
        download stats as csv
      </i18n.Translate></a>
    </div>
  </Fragment>

}


function MetricValue({ current, previous, spec }: { spec: CurrencySpecification, current: AmountString | undefined, previous: AmountString | undefined }): VNode {
  const { i18n } = useTranslationContext()
  const cmp = current && previous ? Amounts.cmp(current, previous) : 0;
  const cv = !current ? undefined : Amounts.stringifyValue(current)
  const currAmount = !cv ? undefined : Number.parseFloat(cv)
  const prevAmount = !previous ? undefined : Number.parseFloat(Amounts.stringifyValue(previous))

  const rate = !currAmount || Number.isNaN(currAmount) || !prevAmount || Number.isNaN(prevAmount) ? 0 :
    cmp === -1 ? 1 - Math.round(currAmount) / Math.round(prevAmount) :
      cmp === 1 ? (Math.round(currAmount) / Math.round(prevAmount)) - 1 : 0;

  const negative = cmp === 0 ? undefined : cmp === -1
  const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`
  return <Fragment>
    <dd class="mt-1 block ">
      <div class="flex justify-start text-2xl items-baseline font-semibold text-indigo-600">
        {!current ? "-" : <RenderAmount value={Amounts.parseOrThrow(current)} spec={spec} hideSmall />}
      </div>
      <div class="flex flex-col">

        <div class="flex justify-end items-baseline text-2xl font-semibold text-indigo-600">
          <small class="ml-2 text-sm font-medium text-gray-500">
            <i18n.Translate>from</i18n.Translate> {!previous ? "-" : <RenderAmount value={Amounts.parseOrThrow(previous)} spec={spec} hideSmall />}
          </small>
        </div>
        {!!rate &&
          <span data-negative={negative} class="flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 text-green-800 data-[negative=true]:bg-red-100 px-2 py-1 text-xs font-medium data-[negative=true]:text-red-700 whitespace-pre">
            {negative ?
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                <path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75" />
              </svg>
              :
              <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
                <path stroke-linecap="round" stroke-linejoin="round" d="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75" />
              </svg>
            }

            {negative ?
              <span class="sr-only"><i18n.Translate>Descreased by</i18n.Translate></span> :
              <span class="sr-only"><i18n.Translate>Increased by</i18n.Translate></span>
            }
            {rateStr}
          </span>
        }
      </div>

    </dd>
  </Fragment>
}
