import { useEffect, useState } from '@wordpress/element';
import { Button } from '@wordpress/components';

import {
  Modal,
  ModalClose,
  ModalContent,
  ModalFooter,
  ModalTrigger,
  ModalHeader,
  ModalTitle,
} from '@components/ui/Modal';

import classNames from 'classnames';
import apiFetch from '@wordpress/api-fetch';
import { ScrollList } from '@components/ui/ScrollList';
import { ToggleSwitch } from '@components/ui/ToggleSwitch';
import { BlockCategory } from './types';
import { Notice } from '@components/ui/Notice';
// @ts-ignore
import { nanoid } from 'nanoid';

const calculateAspectRatio = (width: number, height: number): string => {
  const ratio = width / height;
  const aspectRatios = [
    { name: 'aspect-4/3', ratio: 4 / 3 },
    { name: 'aspect-16/9', ratio: 16 / 9 },
    { name: 'aspect-21/9', ratio: 21 / 9 },
    { name: 'aspect-3/4', ratio: 3 / 4 },
    { name: 'aspect-5/4', ratio: 5 / 4 },
    { name: 'aspect-16/10', ratio: 16 / 10 },
    { name: 'aspect-2/1', ratio: 2 / 1 },
    { name: 'aspect-1/1', ratio: 1 / 1 },
  ];

  let closest = 'aspect-1/1'; // Default aspect ratio
  let minDiff = Infinity;

  aspectRatios.forEach(({ name, ratio: refRatio }) => {
    const diff = Math.abs(ratio - refRatio);
    if (diff < minDiff) {
      minDiff = diff;
      closest = name;
    }
  });

  return closest;
};

const calculateScale = (
  width: number,
  height: number,
  tileWidth: number,
  tileHeight: number,
  colSpan: string
): string => {
  let scaleFactor = Math.min(tileWidth / width, tileHeight / height);

  // Increase scale factor by 0.2 if colSpan is 'col-span-2'
  if (colSpan === 'col-span-2') {
    scaleFactor = Math.min(scaleFactor + 0.2, 1); // Ensure it doesn't exceed 1
  }

  const scaleValues = [
    { factor: 0.1, scale: 'scale-10' },
    { factor: 0.2, scale: 'scale-20' },
    { factor: 0.3, scale: 'scale-30' },
    { factor: 0.4, scale: 'scale-40' },
    { factor: 0.5, scale: 'scale-50' },
    { factor: 0.6, scale: 'scale-60' },
    { factor: 0.7, scale: 'scale-70' },
    { factor: 0.8, scale: 'scale-80' },
    { factor: 0.9, scale: 'scale-90' },
  ];

  // Find the closest matching scale factor
  const closestScale = scaleValues.reduce((prev, curr) =>
    Math.abs(scaleFactor - curr.factor) < Math.abs(scaleFactor - prev.factor)
      ? curr
      : prev
  );

  return closestScale.scale;
};

const calculateColSpan = (width: number): string => {
  if (width >= 800) return 'col-span-2';
  return '';
};

export const BitesLibrary = () => {
  const [blocks, setBlocks] = useState([]);
  const [selectedCategory, setSelectedCategory] = useState(null);
  const [navigation, setNavigation] = useState([]);
  const [open, setOpen] = useState(false);
  const [blockSelection, setBlockSelection] = useState([]);

  const [componentMode, setComponentMode] = useState(true);

  useEffect(() => {
    apiFetch({ path: `${blockbite.api}/bites/library` }).then((result: any) => {
      if (result.navigation.length === 0) return;
      setNavigation(result.navigation);
      setSelectedCategory(result.navigation[0].post_id);
    });
  }, []);

  const insertBlocks = () => () => {
    // Helper function to update the bitesId for a block and its inner blocks
    const updateBitesId = (block: any) => {
      // Update the bitesId of the current block
      if (block.attributes) {
        block.attributes.bitesId = `bit_${nanoid(8)}`;
      }

      // If the block has innerBlocks, recursively update their bitesId as well
      if (block.innerBlocks && block.innerBlocks.length > 0) {
        block.innerBlocks = block.innerBlocks.map(updateBitesId);
      }

      return block;
    };

    // Parse the block data
    const parseBlocks = [];

    blockSelection.forEach((id) => {
      const block = blocks.find((block) => block.id === id);

      let parsedBlock = wp.blocks.parse(
        componentMode ? block.component : block.raw
      );
      // Update the bitesId for each parsed block and its inner blocks
      parsedBlock = parsedBlock.map(updateBitesId);
      if (parsedBlock.length) {
        parseBlocks.push(parsedBlock[0]);
      }
    });

    const insert = wp.data.select('core/block-editor').getBlockInsertionPoint();
    if (insert.rootClientId && insert.index !== undefined) {
      wp.data
        .dispatch('core/block-editor')
        .insertBlocks(parseBlocks, insert.index, insert.rootClientId, true);
    } else {
      wp.data.dispatch('core/block-editor').insertBlocks(parseBlocks);
    }
  };

  const addBlockSelection = (blockId: string) => {
    if (blockSelection.includes(blockId)) {
      setBlockSelection(blockSelection.filter((id: string) => id !== blockId));
    } else {
      setBlockSelection([...blockSelection, blockId]);
    }
  };

  const selectAllBlocks = () => {
    const allBlockIds = blocks.map((block) => block.id);
    setBlockSelection(allBlockIds);
  };

  useEffect(() => {
    if (!selectedCategory) return;
    apiFetch({
      path: `${blockbite.api}/bites/blocks/${selectedCategory}`,
    }).then((result: any) => {
      const blocks = result.blocks.map((block: any) => {
        const { width, height } = block;
        const aspectRatio = calculateAspectRatio(width, height);
        const colspan = calculateColSpan(width);
        const scale = calculateScale(width, height, 400, 400, colspan);

        return {
          ...block,
          aspectRatio,
          scale,
          colspan,
        };
      });

      setBlocks(blocks);
    });
  }, [selectedCategory]);

  return (
    <Modal
      defaultOpen={open}
      onOpenChange={(isOpen: boolean) => {
        setOpen(isOpen);
      }}
    >
      <ModalTrigger>
        <Button className="is-primary flex items-center justify-center">
          <span>Design Library</span>
        </Button>
      </ModalTrigger>
      <ModalContent className="sm:max-w-5xl">
        <ModalHeader>
          <ModalTitle>Block Library</ModalTitle>
        </ModalHeader>
        <div className="border-gray-light -mx-6 flex border-b border-t px-6">
          <div className="border-gray-light -ml-2 flex flex-col overflow-y-auto border-r bg-white py-4 pr-4">
            <div className="flex flex-grow flex-col">
              {navigation.map((category: BlockCategory, index: number) => (
                <Button
                  key={`category__${category.post_id}${index}`}
                  onClick={() => setSelectedCategory(category.post_id)}
                  className={classNames(
                    'text-sm',
                    selectedCategory === index
                      ? 'text-blue-600'
                      : 'text-gray-600'
                  )}
                >
                  {category.name}
                </Button>
              ))}
            </div>
          </div>
          <div className="min-h-[480px] flex-1 p-4">
            <div className="flex w-full justify-between gap-4">
              <ToggleSwitch
                label={componentMode ? 'Component Mode' : 'Block Mode'}
                checked={componentMode}
                onChange={setComponentMode}
              />
              <Notice className="mb-4">
                {componentMode
                  ? `Change block styles fromout your`
                  : 'Changed block styles should be applied to each block'}
              </Notice>
            </div>
            <ScrollList>
              <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-2">
                {blocks.length === 0 && <p>No blocks found in the library.</p>}
                {blocks.map((block: any) => (
                  <div
                    key={`block__${block.id}`}
                    className={classNames(
                      block.aspectRatio,
                      block.colspan,
                      // if in selected blocks add  'border-wordpress'
                      blockSelection.includes(block.id)
                        ? 'border-wordpress'
                        : 'border-gray-light',
                      'group relative flex cursor-pointer items-center justify-center overflow-hidden rounded-md border hover:bg-easy'
                    )}
                    onClick={() => addBlockSelection(block.id)}
                  >
                    <div
                      className={classNames(block.scale, 'origin-center')}
                      id="b_"
                    >
                      <div
                        style={{
                          width: `${block.width}px`,
                          height: `${block.height}px`,
                        }}
                        dangerouslySetInnerHTML={{ __html: block.preview }}
                        className={classNames(
                          'editor-styles-wrapper pointer-events-none !p-0 after:absolute after:left-0 after:top-0 after:z-10 after:h-full after:w-full after:bg-white after:bg-opacity-0'
                        )}
                      />
                    </div>

                    <h4 className="my-2 block">{block.name}</h4>
                  </div>
                ))}
              </div>
            </ScrollList>
          </div>
        </div>
        <ModalFooter className="flex items-center justify-end gap-4">
          {<small>selected {blockSelection.length} blocks</small>}
          {blockSelection.length > 0 && (
            <Button onClick={() => setBlockSelection([])}>
              Clear selection
            </Button>
          )}
          {blockSelection.length !== blocks.length && (
            <Button onClick={() => selectAllBlocks()}>Select all</Button>
          )}
          <Button
            className="component-button is-primary"
            onClick={insertBlocks()}
          >
            Insert {componentMode ? 'Component' : 'Block'}
          </Button>
          <ModalClose>
            <Button>Cancel</Button>
          </ModalClose>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
};

export default { BitesLibrary };
