import { useCallback, useState } from 'react';

import { Box, Button, Flex, Input, Table, Text } from '@chakra-ui/react';
import { LuTrash } from 'react-icons/lu';
import { MdCloudUpload } from 'react-icons/md';

import {
  Season,
  SeasonResource,
  Series,
  SeriesResource,
  Type,
  TypeResource
} from '@/back-api';
import { PageLayout } from '@/components/Layout/PageLayout';
import { TopBar } from '@/components/TopBar/TopBar';
import { FormSelect } from '@/components/form/FormSelect';
import { Formidable, useFormidable } from '@/components/formidable';
import { PopUpUploadProgress } from '@/components/popup/PopUpUploadProgress';
import {
  NumberInputField,
  NumberInputRoot,
} from '@/components/ui/number-input';
import { useMediaService } from '@/service/Media';
import { useOrderedSeasons, useSeasonService } from '@/service/Season';
import { useOrderedSeries, useSeriesService } from '@/service/Series';
import { useServiceContext } from '@/service/ServiceContext';
import { useOrderedTypes, useTypeService } from '@/service/Type';
import { isNullOrUndefined } from '@/utils/validator';

export class ElementList {
  constructor(
    public id?: number,
    public label?: string
  ) {
    // nothing to do.
  }
}
export class FileParsedElement {
  public isSended: boolean = false;
  public nameDetected: boolean = false;
  public MediaIdDetected: boolean = false;
  constructor(
    public uniqueId: number,
    public file: File,
    public title: string,
    public Series?: string,
    public Season?: string,
    public MediaId?: number
  ) {
    console.log(`Unique element: ${uniqueId}`);
    // nothing to do.
  }
}
export class FileFailParsedElement {
  constructor(
    public uniqueId: number,
    public file: File,
    public reason: string
  ) {
    console.log(`Unique element2: ${uniqueId}`);
    // nothing to do.
  }
}

type FormInsertData = {
  TypeId?: number;
  SeriesId?: number;
  titleSeason?: string;
};

export const AddPage = () => {
  const [parsedElement, setParsedElement] = useState<FileParsedElement[]>([]);
  const [parsedFailedElement, setParsedFailedElement] = useState<
    FileFailParsedElement[] | undefined
  >(undefined);

  const [needSend, setNeedSend] = useState<boolean>(false);

  // list of all files already registered in the bdd to compare with the current list of files.
  const [listFileInBdd, setListFileInBdd] = useState<any[] | undefined>(
    undefined
  );

  const { dataTypes } = useOrderedTypes();
  const { dataSeries } = useOrderedSeries();
  const { dataSeasons } = useOrderedSeasons();
  const { store: storeType } = useTypeService();
  const { store: storeSeries } = useSeriesService();
  const { store: storeSeason } = useSeasonService();
  const { store: storeMedia } = useMediaService();
  const { session } = useServiceContext();

  const form = useFormidable<FormInsertData>({
    configuration: {
      enableModifyNotification: false,
      enableReset: false,
    },
  });

  const updateNeedSend = () => {
    if (parsedElement.length === 0) {
      setNeedSend(false);
      return;
    }
    let tmp = true;
    for (let iii = 0; iii < parsedElement.length; iii++) {
      if (
        isNullOrUndefined(parsedElement[iii].title) ||
        parsedElement[iii].title === ''
      ) {
        tmp = false;
      }
    }
    setNeedSend(tmp);
  };

  const onTitle = (data: FileParsedElement, value: any): void => {
    data.title = value;
    setParsedElement([...parsedElement]);
    updateNeedSend();
  };

  const removeElementFromList = (data: FileParsedElement, value: any): void => {
    const parsedElementTmp = [...parsedElement];
    for (let iii = 0; iii < parsedElementTmp.length; iii++) {
      if (parsedElementTmp[iii] === data) {
        parsedElementTmp.splice(iii, 1);
        break;
      }
    }
    setParsedElement(parsedElementTmp);
    setParsedFailedElement((previous) => [
      ...(previous ?? []),
      new FileFailParsedElement(
        previous?.length ?? 0,
        data.file,
        'Removed by user.'
      ),
    ]);
    updateNeedSend();
  };

  const onMediaId = (data: FileParsedElement, value: any): void => {
    data.MediaId = value;
    setParsedElement([...parsedElement]);
    updateNeedSend();
  };

  const clearData = () => {
    setParsedElement([]);
    setParsedFailedElement(undefined);
    setListFileInBdd(undefined);

    setSuggestedSeries(undefined);
    setSuggestedSeason(undefined);
  };

  const addFileWithMetaData = (file: File, id: number) => {
    // parsedElement: FileParsedElement[] = [];
    let Series: string | undefined = undefined;
    let Season: string | undefined = undefined;
    let MediaIdNumber: number | undefined = undefined;
    let title: string = '';

    form.restoreValues();

    console.log(`select file ${file.name}`);
    let tmpName = file.name.replace(/[ \t]*-[ \t]*/g, '-');
    //tmpName = tmpName.replace(/_/g, '-');
    //tmpName = tmpName.replace(/--/g, '-');
    console.log(`select file ${tmpName}`);
    const splitElement = tmpName.split('~');
    if (splitElement.length > 1) {
      Series = splitElement[0];
      tmpName = tmpName.substring(Series.length + 1);
    }
    const splitElement2 = tmpName.split('#');
    if (splitElement2.length > 1) {
      Season = splitElement2[0];
      tmpName = tmpName.substring(Season.length + 1);
    }
    //console.log("ploppppp " + tmpName);
    const splitElement3 = tmpName.split('-');
    if (splitElement3.length > 1) {
      MediaIdNumber = parseInt(splitElement3[0], 10);
      tmpName = tmpName.substring(splitElement3[0].length + 1);
    }
    //console.log("KKKppppp " + tmpName);
    //console.log("    ===> " + splitElement3[0]);
    title = tmpName;

    if (MediaIdNumber && isNaN(MediaIdNumber)) {
      MediaIdNumber = undefined;
    }
    // remove extension
    title = title.replace(new RegExp('\\.(webm|WEBM|Webm)'), '');
    let tmp = new FileParsedElement(
      id,
      file,
      title,
      Series,
      Season,
      MediaIdNumber
    );
    console.log(`==>${JSON.stringify(tmp)}`);
    // add it in the list.
    return tmp;
  };
  const [suggestedSeries, setSuggestedSeries] = useState<string | undefined>(
    undefined
  );
  const [suggestedSeason, setSuggestedSeason] = useState<string | undefined>(
    undefined
  );

  const onChangeFile = (value: any): void => {
    clearData();

    const parsedElementTmp: FileParsedElement[] = [];
    const parsedFailedElementTmp: FileFailParsedElement[] = [];

    for (let iii = 0; iii < value.target.files?.length; iii++) {
      parsedElementTmp.push(addFileWithMetaData(value.target.files[iii], iii));
    }
    // check if all global parameters are generic:
    if (parsedElementTmp.length === 0) {
      updateNeedSend();
      return;
    }

    // clean different Series:
    for (let iii = 1; iii < parsedElementTmp.length; iii++) {
      console.log(
        `check Series [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[0].Series} !== ${parsedElementTmp[iii].Series}'`
      );
      if (parsedElementTmp[0].Series !== parsedElementTmp[iii].Series) {
        parsedFailedElementTmp.push(
          new FileFailParsedElement(
            parsedFailedElementTmp.length,
            parsedElementTmp[iii].file,
            'Remove from list due to wrong Series value'
          )
        );
        console.log(
          `Remove from list (!= Series) : [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[iii].file.name}'`
        );
        parsedElementTmp.splice(iii, 1);
        iii--;
      }
    }
    // clean different Season:
    for (let iii = 1; iii < parsedElementTmp.length; iii++) {
      console.log(
        `check Season [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[0].Season} !== ${parsedElementTmp[iii].Season}'`
      );
      if (parsedElementTmp[0].Season !== parsedElementTmp[iii].Season) {
        parsedFailedElementTmp.push(
          new FileFailParsedElement(
            parsedFailedElementTmp.length,
            parsedElementTmp[iii].file,
            'Remove from list due to wrong Season value'
          )
        );
        console.log(
          `Remove from list (!= Season) : [${iii + 1}/${parsedElementTmp.length}] '${parsedElementTmp[iii].file.name}'`
        );
        parsedElementTmp.splice(iii, 1);
        iii--;
      }
    }
    setParsedElement(parsedElementTmp);
    setParsedFailedElement(parsedFailedElementTmp);
    console.log(`check : ${JSON.stringify(parsedElementTmp[0])}`);

    // find SeriesId:
    console.log(`try find Series : ${parsedElementTmp[0].Series}`);
    let SeriesFound = false;
    dataSeries.forEach((data) => {
      if (
        data.name?.toLowerCase() === parsedElementTmp[0].Series?.toLowerCase()
      ) {
        console.log(`    find Series : ${data.id}`);
        form.setValues({ SeriesId: data.id });
        SeriesFound = true;
      }
    });
    if (!SeriesFound) {
      console.log(`    set Suggested Series : ${parsedElementTmp[0].Series}`);
      setSuggestedSeries(parsedElementTmp[0].Series);
    } else {
      setSuggestedSeries(undefined);
    }
    // try to find Season
    console.log(`try find Season : ${parsedElementTmp[0].Season}`);
    let SeasonFound = false;
    dataSeasons.forEach((data) => {
      if (
        data.name?.toLowerCase() === parsedElementTmp[0].Season?.toLowerCase()
      ) {
        console.log(`    find Season : ${data.id}`);
        form.setValues({ SeasonId: data.id });
        SeasonFound = true;
      }
    });
    if (!SeasonFound) {
      console.log(`    set Suggested Season : ${parsedElementTmp[0].Season}`);
      setSuggestedSeason(parsedElementTmp[0].Season);
    }
    updateNeedSend();
  };

  const [indexUpload, setIndexUpload] = useState<number | undefined>(undefined);
  const [listValues, setListValues] = useState<string[]>([]);
  const [currentPosition, setCurrentPosition] = useState<number>(0);
  const [totalPosition, setTotalPosition] = useState<number>(0);
  const [uploadError, setUploadError] = useState<string | undefined>(undefined);
  const [isFinishedUpload, setIsFinishedUpload] = useState<boolean>(false);

  const progressUpload = useCallback(
    (count: number, total: number) => {
      setTotalPosition(total);
      setCurrentPosition(count);
    },
    [setTotalPosition, setCurrentPosition]
  );

  const uploadNext = useCallback(
    (index: number = 0): void => {
      if (parsedElement.length <= index) {
        console.log('end of upload');
        setIsFinishedUpload(true);
        return;
      }
      setIndexUpload(index);
      console.log(
        `Start upload of file:  ${index}: ${parsedElement[index].title} ==> ${JSON.stringify(parsedElement[index], null, 2)}`
      );
      const data = {
        title: parsedElement[index].title,
        file: parsedElement[index].file,
        SeasonId: form.values['SeasonId'] ?? undefined,
        SeriesId: form.values['SeriesId'] ?? undefined,
        TypeId: form.values['TypeId'] ?? undefined,
        MediaId: parsedElement[index].MediaId ?? undefined,
      };
      console.log(`data= ${JSON.stringify(data, null, 2)}`);
      console.error("Not_ implemented");
      // storeMedia
      //   .update(
      //     MediaResource.uploadMedia({
      //       restConfig: session.getRestConfig(),
      //       data,
      //       callbacks: {
      //         progressUpload: progressUpload,
      //       },
      //     })
      //   )
      //   .then((data: Media) => {
      //     // element sended good
      //     // Send next ...
      //     uploadNext(index + 1);
      //   })
      //   .catch((error: RestErrorResponse) => {
      //     // TODO: manage error
      //     console.log(`element error: ${JSON.stringify(error, null, 2)}`);
      //     setUploadError(JSON.stringify(error, null, 2));
      //   });
    },
    [
      setUploadError,
      setIndexUpload,
      storeMedia,
      parsedElement,
      form,
      form.values,
    ]
  );

  const sendFile = (_data): void => {
    console.log(`Send file requested ... ${parsedElement.length}`);
    setUploadError(undefined);
    setIsFinishedUpload(false);
    setListValues(parsedElement.map((element) => element.file.name));
    uploadNext();
  };

  function onUploadAbort(): void {
    setIndexUpload(undefined);
  }

  function OnUploadClose(): void {
    setIndexUpload(undefined);
  }

  const addNewType = (data: string): Promise<Type> => {
    return storeType.update(
      TypeResource.post({
        restConfig: session.getRestConfig(),
        data: {
          name: data,
        },
      })
    );
  };
  const addNewSeries = (data: string): Promise<Series> => {
    return storeSeries.update(
      SeriesResource.post({
        restConfig: session.getRestConfig(),
        data: {
          name: data,
        },
      })
    );
  };
  const addNewSeason = (data: string): Promise<Season> => {
    return storeSeason.update(
      SeasonResource.post({
        restConfig: session.getRestConfig(),
        data: {
          name: data,
        },
      })
    );
  };

  return (
    <>
      <TopBar title="Add new media" />
      <PageLayout>
        <Flex
          direction="column"
          width="80%"
          marginX="auto"
          padding="10px"
          gap="10px"
        >
          <Flex direction="column" width="full">
            <Flex>
              <Text flex={1}>format:</Text>
              <Text flex={4}>
                The format of the media permit to automatic find meta-data:
                <br />
                Series~Season#idMedia-my name of my media.webm
                <br />
                <b>example:</b> Clarika~Moi En Mieux#22-des bulles.webm
              </Text>
            </Flex>
            <Flex>
              <Text flex={1}>Media:</Text>
              <Input
                flex={4}
                type="file"
                placeholder="Select a media file"
                accept=".webm"
                multiple
                onChange={onChangeFile}
              />
            </Flex>
          </Flex>
          {parsedElement && parsedElement.length !== 0 && (
            <Formidable.From form={form} onSubmit={sendFile}>
              <Text fontSize="30px">Meta-data:</Text>
              <FormSelect
                label="Type"
                name="TypeId"
                options={dataTypes}
                addNewItem={addNewType}
              />
              <FormSelect
                label="Series"
                name="SeriesId"
                options={dataSeries}
                addNewItem={addNewSeries}
                suggestion={suggestedSeries}
              />
              <FormSelect
                label="Season"
                name="SeasonId"
                options={dataSeasons}
                addNewItem={addNewSeason}
                suggestion={suggestedSeason}
              />
              <Table.Root
                colorPalette="striped"
                colorScheme="teal"
                background="gray.700"
              >
                <Table.Header>
                  <Table.Row>
                    <Table.ColumnHeader width="10%">
                      Media ID
                    </Table.ColumnHeader>
                    <Table.ColumnHeader width="full">Title</Table.ColumnHeader>
                    <Table.ColumnHeader>actions</Table.ColumnHeader>
                  </Table.Row>
                </Table.Header>
                <Table.Body>
                  {parsedElement.map((data) => (
                    <Table.Row key={data.uniqueId}>
                      <Table.Cell>
                        <NumberInputRoot
                          value={data.MediaId ? `${data.MediaId}` : undefined}
                          onValueChange={(e) => onMediaId(data, e.value)}
                          min={0}
                          max={5000}
                          backgroundColor={
                            data.MediaIdDetected === true
                              ? 'darkred'
                              : undefined
                          }
                        >
                          <NumberInputField />
                        </NumberInputRoot>
                      </Table.Cell>
                      <Table.Cell>
                        <Input
                          type="text"
                          placeholder="Name of the Media"
                          value={data.title}
                          onChange={(e) => onTitle(data, e.target.value)}
                          backgroundColor={
                            data.title === '' ? 'darkred' : undefined
                          }
                        />
                        {data.nameDetected === true && (
                          <>
                            <br />
                            <Text as="span" color="@danger">
                              ^^^This title already exist !!!
                            </Text>
                          </>
                        )}
                      </Table.Cell>
                      <Table.Cell>
                        <Button
                          colorPalette="@danger"
                          onClick={(e) => removeElementFromList(data, e.target)}
                        >
                          <LuTrash /> Remove
                        </Button>
                      </Table.Cell>
                    </Table.Row>
                  ))}
                </Table.Body>
              </Table.Root>
              <Flex marginY="15px">
                <Button
                  colorPalette="brand"
                  type="submit"
                  disabled={!needSend}
                  marginLeft="auto"
                  marginRight="30px"
                >
                  <MdCloudUpload /> Upload
                </Button>
              </Flex>
            </Formidable.From>
          )}

          {listFileInBdd && (
            <Table.Root
              fontPalette="striped"
              colorScheme="teal"
              background="gray.700"
            >
              <Table.Header>
                <Table.Row>
                  <Table.ColumnHeader>Media ID</Table.ColumnHeader>
                  <Table.ColumnHeader width="full">Title</Table.ColumnHeader>
                  <Table.ColumnHeader>actions</Table.ColumnHeader>
                </Table.Row>
              </Table.Header>
              <Table.Body>
                {listFileInBdd.map((data) => (
                  <Table.Row>
                    <Table.Cell>
                      <Text
                        color={
                          data.episodeDetected === true ? 'red' : undefined
                        }
                      >
                        {data.MediaId}
                      </Text>
                    </Table.Cell>
                    <Table.Cell>
                      <Text
                        color={data.nameDetected === true ? 'red' : undefined}
                      >
                        {data.title}
                      </Text>
                    </Table.Cell>
                    <Table.Cell></Table.Cell>
                  </Table.Row>
                ))}
              </Table.Body>
            </Table.Root>
          )}

          {parsedFailedElement && (
            <>
              <Text fontSize="30px">Rejected:</Text>
              <Table.Root
                colorPalette="striped"
                colorScheme="teal"
                background="gray.700"
              >
                <Table.Header>
                  <Table.Row>
                    <Table.ColumnHeader maxWidth="80%">file</Table.ColumnHeader>
                    <Table.ColumnHeader>Reason</Table.ColumnHeader>
                  </Table.Row>
                </Table.Header>
                <Table.Body>
                  {parsedFailedElement.map((data) => (
                    <Table.Row key={data.uniqueId}>
                      <Table.Cell>{data.file.name}</Table.Cell>
                      <Table.Cell>{data.reason}</Table.Cell>
                    </Table.Row>
                  ))}
                </Table.Body>
              </Table.Root>
            </>
          )}
          <Box height="250px" width="full" />
        </Flex>
        {indexUpload !== undefined && (
          <PopUpUploadProgress
            title="Upload File(s)"
            currentSize={currentPosition}
            totalSize={totalPosition}
            index={indexUpload}
            elements={listValues}
            error={uploadError}
            onAbort={onUploadAbort}
            onClose={OnUploadClose}
            isFinished={isFinishedUpload}
          />
        )}
      </PageLayout>
    </>
  );
};
