/*
 This file is part of GNU Taler
 (C) 2025 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 <http://www.gnu.org/licenses/>
 */

import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useTranslationContext } from "../../index.browser.js";
import { UIFormProps } from "../FormProvider.js";
import { FileFieldData } from "../forms-types.js";
import { noHandlerPropsAndNoContextForField } from "./InputArray.js";
import { LabelWithTooltipMaybeRequired } from "./InputLine.js";

export function InputFile(
  props: { maxBites: number; accept?: string } & UIFormProps<FileFieldData>,
): VNode {
  const { i18n } = useTranslationContext();
  const { label, tooltip, required, help: propsHelp, maxBites, accept } = props;
  const { value, onChange } =
    props.handler ?? noHandlerPropsAndNoContextForField(props.name);

  const help = propsHelp;
  if (props.hidden) {
    return <Fragment />;
  }

  const [dataUri, setDataUri] = useState<string | undefined>(() => {
    if (!value) {
      return undefined;
    }
    if (value.ENCODING != "base64") {
      throw Error("unsupported file storage type");
    }
    return `data:${value.MIME_TYPE ?? "application/octet-stream"};base64,${
      value.CONTENTS
    }`;
  });

  const handleFile = (
    contentsBase64?: string,
    mimeType?: string,
    filename?: string,
  ) => {
    // console.log(`handleFile`, contentsBase64, mimeType, filename);
    if (contentsBase64 == null) {
      setDataUri(undefined);
      onChange(undefined);
      return;
    }
    setDataUri(`data:${mimeType}};base64,${contentsBase64}`);
    onChange({
      CONTENTS: contentsBase64,
      ENCODING: "base64",
      FILENAME: filename,
      MIME_TYPE: mimeType,
    });
  };

  return (
    <div class="col-span-full">
      <LabelWithTooltipMaybeRequired
        label={label}
        tooltip={tooltip}
        required={required}
        name={props.name as string}
      />
      {!value ? (
        <div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 py-1">
          <div class="text-center">
            <svg
              class="mx-auto h-12 w-12 text-gray-300"
              viewBox="0 0 24 24"
              fill="currentColor"
              aria-hidden="true"
            >
              <path
                fill-rule="evenodd"
                d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z"
                clip-rule="evenodd"
              />
            </svg>
            {!props.disabled && (
              <div class="my-2 flex text-sm leading-6 text-gray-600">
                <label
                  for={String(props.name)}
                  class="relative cursor-pointer rounded-md bg-white font-semibold text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 hover:text-indigo-500"
                >
                  <span>
                    <i18n.Translate>Upload a file</i18n.Translate>
                  </span>
                  <input
                    id={String(props.name)}
                    type="file"
                    class="sr-only"
                    accept={accept}
                    onChange={(e) => {
                      const f: FileList | null = e.currentTarget.files;
                      if (!f || f.length != 1) {
                        handleFile(undefined);
                        return;
                      }
                      if (f[0].size > maxBites) {
                        handleFile(undefined);
                        return;
                      }
                      const fileName = f[0].name;
                      return f[0].arrayBuffer().then((b) => {
                        const b64 = window.btoa(
                          new Uint8Array(b).reduce(
                            (data, byte) => data + String.fromCharCode(byte),
                            "",
                          ),
                        );
                        handleFile(b64, f[0].type, fileName);
                      });
                    }}
                  />
                </label>
                {/* <p class="pl-1">or drag and drop</p> */}
              </div>
            )}
          </div>
        </div>
      ) : (
        <Fragment>
          <div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 relative">
            {value.MIME_TYPE?.startsWith("image/") ? (
              <Fragment>
                <img src={dataUri} class=" h-24 w-full object-cover relative" />
                {value.FILENAME ? (
                  <div class="absolute rounded-lg border flex justify-center text-xl items-center text-white ">
                    {value.FILENAME}
                  </div>
                ) : (
                  <Fragment />
                )}
              </Fragment>
            ) : (
              <div class="h-24 w-full object-cover relative p-2">
                <div class="flex flex-row">
                  <svg
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke-width="1.5"
                    stroke="currentColor"
                    class="size-6"
                  >
                    <path
                      stroke-linecap="round"
                      stroke-linejoin="round"
                      d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Z"
                    />
                  </svg>

                  {value.FILENAME ? (
                    <div class=" flex justify-center text-xl items-center ">
                      {value.FILENAME}
                    </div>
                  ) : (
                    <div />
                  )}
                </div>
              </div>
            )}

            {!props.disabled && (
              <div
                class="opacity-0 hover:opacity-70 duration-300 absolute rounded-lg border inset-0 z-10 flex justify-center text-xl items-center bg-black text-white cursor-pointer "
                onClick={() => {
                  handleFile(undefined);
                }}
              >
                Clear
              </div>
            )}
          </div>
          <a
            class="font-semibold text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 hover:text-indigo-500"
            href={`data:${value.MIME_TYPE};${value.ENCODING},${value.CONTENTS}`}
            download={value.FILENAME}
            onClick={(e) => {
              return false;
            }}
          >
            <i18n.Translate>Download a copy.</i18n.Translate>
          </a>
        </Fragment>
      )}
      {help && <p class="text-xs leading-5 text-gray-600 mt-2">{help}</p>}
    </div>
  );
}
