import { useState, useEffect, useCallback, memo } from '@wordpress/element';
import { Button, SelectControl, Disabled } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import type { ResponseProps } from '@components/DesignPanel/types';
import {
  Notice,
  Spinner,
  TextControl,
  ToggleControl,
} from '@wordpress/components';
import { TabsWrapper, TabsContent, TabsList } from '@components/ui/Tabs';

import has from 'lodash/has';
import {
  Modal,
  ModalClose,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalTitle,
  ModalTrigger,
} from '@components/ui/Modal';
import { DisappearingMessage } from '@components/ui/DisappearingMessage';
import { useSelect } from '@wordpress/data';

import PageIcon from 'blockbite-icons/dist/Pencil1';
import { Icon as IconComp } from '@components/ui/Icon';

export type DesignTokenProp = {
  token: string;
  value: string;
  name: string;
  optional?: any;
};

export type DesignTokenProps = {
  fontSizes: any[];
  colors: any[];
  fonts: any[];
  headings: any[];
};

export type DesignTokenOptinProps = {
  colors: boolean;
  fonts: boolean;
  fontSizes: boolean;
  headings: boolean;
};

const FONTSIZESLOTS = 16;
const COLORSSLOTS = 16;
const FONTSSLOTS = 10;
const HEADINGSLOTS = 7;

export const createSlots = (themeValues: any) => {
  const {
    colors: colorValues = [],
    fonts: fontsValues = [],
    fontSizes: fontSizesValues = [],
    headings: headingsValues = [],
  } = themeValues;

  const createSlotsArray = (
    count: number,
    tokenPrefix: string,
    names: string[]
  ) => {
    return Array.from({ length: count }, (_, i) => ({
      token: `${tokenPrefix}-${i + 1}`,
      value: '',
      name: names.length ? names[i] : `${tokenPrefix}-${i + 1}`,
      optional: {},
    }));
  };

  // Generate slots for each category with specified lengths
  const fontSizes = createSlotsArray(FONTSIZESLOTS, 'b_fontsize', []);
  const colors = createSlotsArray(COLORSSLOTS, 'b_color', []);
  const fonts = createSlotsArray(FONTSSLOTS, 'b_font', []);
  const headings = createSlotsArray(HEADINGSLOTS, 'b_heading', [
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'p',
  ]);

  const populateSlots = (slots: any[], data: any[]) => {
    (data || []).forEach((item, index) => {
      if (slots[index]) {
        slots[index].value = item.value || '';
        slots[index].name = item.name || slots[index].name;
        if (item.optional) {
          slots[index].optional = { ...item.optional };
        }
      }
    });
  };

  // Populate the slots with provided theme values
  populateSlots(fontSizes, fontSizesValues);
  populateSlots(colors, colorValues);
  populateSlots(fonts, fontsValues);
  populateSlots(headings, headingsValues);

  return { fontSizes, colors, fonts, headings };
};

export const saveDesignTokens = async (
  themeOptin: DesignTokenOptinProps,
  inputFields: DesignTokenProps
) => {
  /*
    get native global styles
    global styles are written as a custom post type in the database if you change the site editor styles
  */
  const nativeGlobalStyles = await apiFetch({
    path: '/blockbite/v1/editor-settings/native-global-styles',
  }).then((res: any) => {
    return res;
  });

  // get slots directly from native theme
  const updatedTheme: DesignTokenProps = {
    ...blockbite.getNativeTheme(nativeGlobalStyles),
  };

  // check any optin is enabled and override them with enabled fields
  if (themeOptin.colors) {
    updatedTheme.colors = inputFields.colors;
  }
  if (themeOptin.fonts) {
    updatedTheme.fonts = inputFields.fonts;
  }
  if (themeOptin.fontSizes) {
    updatedTheme.fontSizes = inputFields.fontSizes;
  }
  if (themeOptin.headings) {
    updatedTheme.headings = inputFields.headings;
  }

  // fill remaining empty slots
  const slotTheme = createSlots(updatedTheme);

  // save current optin state
  apiFetch({
    path: `/blockbite/v1/items/upsert-handle`,
    method: 'POST',
    data: {
      handle: 'design-tokens-optin',
      content: JSON.stringify(themeOptin),
    },
  });

  // save design tokens
  return apiFetch({
    path: `/blockbite/v1/items/upsert-handle`,
    method: 'POST',
    data: {
      handle: 'design-tokens',
      platform: 'site',
      content: JSON.stringify(slotTheme),
    },
  }).then((res: ResponseProps) => {
    if (res.status === 200) {
      // this will trigger to update the tailwind config
      wp.data.dispatch('biteStore/editor').setTheme(slotTheme);
      return res;
    }
  });
};

export const changeThemeOptin = (theme: DesignTokenOptinProps) => {
  apiFetch({
    path: `/blockbite/v1/items/upsert-handle`,
    method: 'POST',
    data: {
      handle: 'design-tokens-optin',
      platform: 'site',
      content: JSON.stringify(theme),
    },
  });
};
const FieldMapper = memo(
  ({
    fieldType,
    inputFields,
    setInputFields,
    themeOptin,
    disableLabels = false,
    setMessage,
  }: any) => {
    const handleInputChange = useCallback(
      (token: any, key: any, value: any) => {
        setInputFields((prevFields: any) => ({
          ...prevFields,
          [fieldType]: prevFields[fieldType].map((item: any) =>
            item.token === token ? { ...item, [key]: value } : item
          ),
        }));
      },
      [fieldType, setInputFields]
    );

    return inputFields[fieldType].map((item: any) => (
      <div
        key={item.token}
        className="my-2"
        onClick={() => {
          if (!themeOptin[fieldType]) {
            setMessage('Please enable custom tokens to edit.');
          }
        }}
      >
        <Disabled isDisabled={!themeOptin[fieldType]}>
          <div className={disableLabels ? '' : 'grid grid-cols-2 gap-4'}>
            {!disableLabels && (
              <TextControl
                type="text"
                label="Name"
                value={item.name}
                onChange={(e) => {
                  if (themeOptin[fieldType]) {
                    handleInputChange(item.token, 'name', e);
                  }
                }}
                help={item.token}
              />
            )}
            {fieldType === 'headings' ? (
              <div className="flex items-center gap-2">
                <div className="flex-1">
                  <SelectControl
                    value={item.value || ''}
                    label="Font Size"
                    options={inputFields.fontSizes.map((item: any) => ({
                      value: item.token,
                      label: item.name,
                    }))}
                    onChange={(token: string) => {
                      if (themeOptin[fieldType]) {
                        const fontFamilyByValue = inputFields.fontSizes.find(
                          (fontFamily: any) => fontFamily.token === token
                        );
                        handleInputChange(
                          item.token,
                          'value',
                          fontFamilyByValue.token
                        );
                      }
                    }}
                    className="w-full"
                  ></SelectControl>
                </div>
                <TextControl
                  label="Line Height"
                  type="text"
                  value={item.optional?.lineHeight || ''}
                  onChange={(e) => {
                    if (themeOptin[fieldType]) {
                      handleInputChange(item.token, 'optional', {
                        ...item.optional,
                        lineHeight: e,
                      });
                    }
                  }}
                  className="w-32 flex-none"
                />
                <div className="flex-1">
                  <SelectControl
                    value={item.optional?.font || ''}
                    label="Font Family"
                    // disabled={inputFields.headings.includes(item)}
                    options={inputFields.fonts.map((item: any) => ({
                      value: item.token,
                      label: item.name,
                    }))}
                    onChange={(token: string) => {
                      if (themeOptin[fieldType]) {
                        const fontFamilyByValue = inputFields.fonts.find(
                          (fontFamily: any) => fontFamily.token === token
                        );
                        handleInputChange(item.token, 'optional', {
                          ...item.optional,
                          font: fontFamilyByValue.token,
                        });
                      }
                    }}
                    className="w-full"
                  ></SelectControl>
                </div>
              </div>
            ) : (
              <TextControl
                type="text"
                label="Value"
                value={item.value}
                onChange={(e) => {
                  if (themeOptin[fieldType]) {
                    handleInputChange(item.token, 'value', e);
                  }
                }}
              />
            )}
          </div>
        </Disabled>
      </div>
    ));
  }
);

export const DesignTokenModal = () => {
  const [open, setOpen] = useState(false);
  const [message, setMessage] = useState<string>('');
  const [saving] = useState(false);
  const [inputFields, setInputFields] = useState({
    colors: [] as any,
    fonts: [] as any,
    fontSizes: [] as any,
    headings: [] as any,
  });
  const [themeOptin, setThemeOptin] = useState({
    colors: false,
    fonts: false,
    fontSizes: false,
    headings: false,
  });

  const themeInit = useSelect((select) => {
    // @ts-ignore
    return select('biteStore/editor').getThemeInit();
  }, []);

  useEffect(() => {
    if (themeInit) {
      const getThemeOptin = wp.data.select('biteStore/editor').getThemeOptin();
      const slots = createSlots(wp.data.select('biteStore/editor').getTheme());
      setInputFields(slots);
      setThemeOptin(getThemeOptin);
    }
  }, [themeInit]);

  return (
    <Modal
      defaultOpen={open}
      onOpenChange={(isOpen: boolean) => {
        setOpen(isOpen);
      }}
    >
      <ModalTrigger>
        <Button className="is-primary flex items-center justify-center">
          <span>Design Tokens</span>
        </Button>
      </ModalTrigger>
      {themeInit && (
        <ModalContent className="blockbite--Modal min-h-[640px] sm:max-w-xl">
          <ModalHeader>
            <ModalTitle>Design Tokens</ModalTitle>
          </ModalHeader>
          {message && (
            <Notice
              status="error"
              key={message}
              onDismiss={() => {
                setMessage('');
              }}
            >
              {message}
            </Notice>
          )}
          <TabsWrapper>
            <TabsList
              options={
                [
                  {
                    title: 'Font Sizes',
                    name: 'fontSizes',
                  },
                  {
                    title: 'Colors',
                    name: 'colors',
                  },
                  {
                    title: 'Headings',
                    name: 'headings',
                  },
                  {
                    title: 'Font Families',
                    name: 'fonts',
                  },
                  {
                    title: 'Sync',
                    name: 'sync',
                  },
                ] as any[]
              }
            />

            <div id="editor" className="my-4 flex flex-col gap-2 px-2">
              <TabsContent value="fontSizes">
                <div className="max-w-sm pb-4">
                  <ToggleControl
                    checked={!!themeOptin?.fontSizes}
                    onChange={(e) => {
                      setThemeOptin({ ...themeOptin, fontSizes: e });
                    }}
                    label="Enable custom font size tokens"
                    help="Customize the font sizes for your theme. Enabling custom font sizes will disable font size token sync."
                  />
                </div>
                <FieldMapper
                  fieldType="fontSizes"
                  inputFields={inputFields}
                  setInputFields={setInputFields}
                  themeOptin={themeOptin}
                  setMessage={setMessage}
                />
              </TabsContent>
              <TabsContent value="colors">
                <div className="max-w-sm pb-4">
                  <ToggleControl
                    checked={!!themeOptin?.colors}
                    onChange={(e) => {
                      setThemeOptin({ ...themeOptin, colors: e });
                    }}
                    label="Enable custom color tokens"
                    help="Customize the colors for your theme. Enabling custom colors will disable color token sync."
                  />
                </div>
                <FieldMapper
                  fieldType="colors"
                  inputFields={inputFields}
                  setInputFields={setInputFields}
                  themeOptin={themeOptin}
                  setMessage={setMessage}
                />
              </TabsContent>
              <TabsContent value="headings">
                <div className="max-w-sm pb-4">
                  <ToggleControl
                    checked={!!themeOptin?.headings}
                    onChange={(e) => {
                      setThemeOptin({ ...themeOptin, headings: e });
                    }}
                    label="Enable custom heading tokens"
                    help="Customize the headings for your theme. Enabling custom headings will disable heading token sync."
                  />
                </div>
                <FieldMapper
                  fieldType="headings"
                  inputFields={inputFields}
                  setInputFields={setInputFields}
                  themeOptin={themeOptin}
                  disableLabels={true}
                  setMessage={setMessage}
                />
              </TabsContent>
              <TabsContent value="fonts">
                <div className="max-w-sm pb-4">
                  <ToggleControl
                    checked={!!themeOptin?.fonts}
                    onChange={(e) => {
                      setThemeOptin({ ...themeOptin, fonts: e });
                    }}
                    label="Enable custom font family tokens"
                    help="Customize the font families for your theme. Enabling custom font families will disable font family token sync."
                  />
                </div>
                <FieldMapper
                  fieldType="fonts"
                  inputFields={inputFields}
                  setInputFields={setInputFields}
                  themeOptin={themeOptin}
                  setMessage={setMessage}
                />
              </TabsContent>
              <TabsContent value="sync">
                <h4 className="font-semibold">Sync Design Tokens</h4>
                <p className="mb-4 max-w-sm">
                  Sync your design tokens from the{' '}
                  <a
                    href="https://wordpress.com/support/site-editor/"
                    target="_blank"
                    rel="noopener noreferrer"
                    className="text-primary underline"
                  >
                    Site Editor
                  </a>{' '}
                  or <strong>theme.json</strong> to blockbite. Syncing will not
                  affect custom design tokens.
                </p>
                <div className="flex items-center gap-3">
                  {themeInit && (
                    <Button
                      variant="primary"
                      icon={<IconComp icon={PageIcon} />}
                      disabled={saving}
                      onClick={() => {
                        saveDesignTokens(themeOptin, inputFields)
                          .then((res: any) => {
                            if (has(res, 'data')) {
                              const content = JSON.parse(res.data.content);
                              const slots = createSlots(content);
                              setInputFields(slots);
                              wp.data
                                .dispatch('biteStore/editor')
                                .setTheme(content);
                            }
                          })
                          .catch(() => {
                            setMessage('Design Tokens Sync Failed');
                          });
                      }}
                    >
                      Sync
                    </Button>
                  )}
                  <div className="flex items-center gap-2">
                    {saving && themeInit && <Spinner className="!m-0" />}
                    <span>
                      {saving && 'Syncing…'}
                      <DisappearingMessage duration={3000} trigger={!saving}>
                        {!saving && (
                          <div className="flex items-center gap-1">
                            <PageIcon />
                            Synced!
                          </div>
                        )}
                      </DisappearingMessage>
                    </span>
                  </div>
                </div>
              </TabsContent>
            </div>
          </TabsWrapper>
          <ModalFooter>
            <ModalClose>
              <Button variant="tertiary">Cancel</Button>
            </ModalClose>
            {themeInit && (
              <Button
                variant="primary"
                disabled={saving}
                onClick={() => {
                  saveDesignTokens(themeOptin, inputFields)
                    .then((res: any) => {
                      if (has(res, 'data')) {
                        const content = JSON.parse(res.data.content);

                        wp.data.dispatch('biteStore/editor').setTheme(content);
                      }
                    })
                    .catch(() => {
                      setMessage('Design Tokens Save Failed');
                    });
                }}
              >
                Save
              </Button>
            )}
          </ModalFooter>
        </ModalContent>
      )}
      {!themeInit && (
        <ModalContent className="blockbite--Modal min-h-[640px] sm:max-w-xl">
          <ModalHeader>
            <ModalTitle>Design Tokens</ModalTitle>
          </ModalHeader>

          <Spinner />
        </ModalContent>
      )}
    </Modal>
  );
};
