/*
 This file is part of GNU Taler
 (C) 2021-2023 Taler Systems S.A.
 GNU Taler is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.
 GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 You should have received a copy of the GNU General Public License along with
 GNU Taler; see the file COPYING.  If not, see 
 */
import {
  HttpResponse,
  HttpResponseOk,
  HttpResponsePaginated,
  RequestError,
} from "@gnu-taler/web-util/browser";
import { useEffect, useState } from "preact/hooks";
import { MerchantBackend } from "../declaration.js";
import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils/constants.js";
import { useBackendInstanceRequest, useMatchMutate } from "./backend.js";
// FIX default import https://github.com/microsoft/TypeScript/issues/49189
import _useSWR, { SWRHook } from "swr";
const useSWR = _useSWR as unknown as SWRHook;
const MOCKED_DEVICES: Record = {
  "1": {
    otp_device_description: "first device",
    otp_algorithm: 1,
    otp_device_id: "1",
    otp_key: "123",
  },
  "2": {
    otp_device_description: "second device",
    otp_algorithm: 0,
    otp_device_id: "2",
    otp_key: "456",
  }
}
export function useOtpDeviceAPI(): OtpDeviceAPI {
  const mutateAll = useMatchMutate();
  const { request } = useBackendInstanceRequest();
  const createOtpDevice = async (
    data: MerchantBackend.OTP.OtpDeviceAddDetails,
  ): Promise> => {
    // MOCKED_DEVICES[data.otp_device_id] = data
    // return Promise.resolve({ ok: true, data: undefined });
    const res = await request(`/private/otp-devices`, {
      method: "POST",
      data,
    });
    await mutateAll(/.*private\/otp-devices.*/);
    return res;
  };
  const updateOtpDevice = async (
    deviceId: string,
    data: MerchantBackend.OTP.OtpDevicePatchDetails,
  ): Promise> => {
    // MOCKED_DEVICES[deviceId].otp_algorithm = data.otp_algorithm
    // MOCKED_DEVICES[deviceId].otp_ctr = data.otp_ctr
    // MOCKED_DEVICES[deviceId].otp_device_description = data.otp_device_description
    // MOCKED_DEVICES[deviceId].otp_key = data.otp_key
    // return Promise.resolve({ ok: true, data: undefined });
    const res = await request(`/private/otp-devices/${deviceId}`, {
      method: "PATCH",
      data,
    });
    await mutateAll(/.*private\/otp-devices.*/);
    return res;
  };
  const deleteOtpDevice = async (
    deviceId: string,
  ): Promise> => {
    // delete MOCKED_DEVICES[deviceId]
    // return Promise.resolve({ ok: true, data: undefined });
    const res = await request(`/private/otp-devices/${deviceId}`, {
      method: "DELETE",
    });
    await mutateAll(/.*private\/otp-devices.*/);
    return res;
  };
  return {
    createOtpDevice,
    updateOtpDevice,
    deleteOtpDevice,
  };
}
export interface OtpDeviceAPI {
  createOtpDevice: (
    data: MerchantBackend.OTP.OtpDeviceAddDetails,
  ) => Promise>;
  updateOtpDevice: (
    id: string,
    data: MerchantBackend.OTP.OtpDevicePatchDetails,
  ) => Promise>;
  deleteOtpDevice: (id: string) => Promise>;
}
export interface InstanceOtpDeviceFilter {
}
export function useInstanceOtpDevices(
  args?: InstanceOtpDeviceFilter,
  updatePosition?: (id: string) => void,
): HttpResponsePaginated<
  MerchantBackend.OTP.OtpDeviceSummaryResponse,
  MerchantBackend.ErrorDetail
> {
  // return {
  //   ok: true,
  //   loadMore: () => { },
  //   loadMorePrev: () => { },
  //   data: {
  //     otp_devices: Object.values(MOCKED_DEVICES).map(d => ({
  //       device_description: d.otp_device_description,
  //       otp_device_id: d.otp_device_id
  //     }))
  //   }
  // }
  const { fetcher } = useBackendInstanceRequest();
  const [pageAfter, setPageAfter] = useState(1);
  const totalAfter = pageAfter * PAGE_SIZE;
  const {
    data: afterData,
    error: afterError,
    isValidating: loadingAfter,
  } = useSWR<
    HttpResponseOk,
    RequestError
  >([`/private/otp-devices`], fetcher);
  const [lastAfter, setLastAfter] = useState<
    HttpResponse<
      MerchantBackend.OTP.OtpDeviceSummaryResponse,
      MerchantBackend.ErrorDetail
    >
  >({ loading: true });
  useEffect(() => {
    if (afterData) setLastAfter(afterData);
  }, [afterData /*, beforeData*/]);
  if (afterError) return afterError.cause;
  // if the query returns less that we ask, then we have reach the end or beginning
  const isReachingEnd =
    afterData && afterData.data.otp_devices.length < totalAfter;
  const isReachingStart = false;
  const pagination = {
    isReachingEnd,
    isReachingStart,
    loadMore: () => {
      if (!afterData || isReachingEnd) return;
      if (afterData.data.otp_devices.length < MAX_RESULT_SIZE) {
        setPageAfter(pageAfter + 1);
      } else {
        const from = `${afterData.data.otp_devices[afterData.data.otp_devices.length - 1]
          .otp_device_id
          }`;
        if (from && updatePosition) updatePosition(from);
      }
    },
    loadMorePrev: () => {
    },
  };
  const otp_devices = !afterData ? [] : (afterData || lastAfter).data.otp_devices;
  if (loadingAfter /* || loadingBefore */)
    return { loading: true, data: { otp_devices } };
  if (/*beforeData &&*/ afterData) {
    return { ok: true, data: { otp_devices }, ...pagination };
  }
  return { loading: true };
}
export function useOtpDeviceDetails(
  deviceId: string,
): HttpResponse<
  MerchantBackend.OTP.OtpDeviceDetails,
  MerchantBackend.ErrorDetail
> {
  // return {
  //   ok: true,
  //   data: {
  //     device_description: MOCKED_DEVICES[deviceId].otp_device_description,
  //     otp_algorithm: MOCKED_DEVICES[deviceId].otp_algorithm,
  //     otp_ctr: MOCKED_DEVICES[deviceId].otp_ctr
  //   }
  // }
  const { fetcher } = useBackendInstanceRequest();
  const { data, error, isValidating } = useSWR<
    HttpResponseOk,
    RequestError
  >([`/private/otp-devices/${deviceId}`], fetcher, {
    refreshInterval: 0,
    refreshWhenHidden: false,
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
    refreshWhenOffline: false,
  });
  if (isValidating) return { loading: true, data: data?.data };
  if (data) {
    return data;
  }
  if (error) return error.cause;
  return { loading: true };
}