import { useState, useEffect, useRef } from '@wordpress/element';
import Editor from '@monaco-editor/react';
import { Button } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import { Notice } from '@wordpress/components';

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

import { createTailwind } from '@core/blockbitePurge';

export const StylesEditorModal = () => {
  const [open, setOpen] = useState(false);
  const [message, setMessage] = useState(null);
  const [saving, setSaving] = useState(false);
  const [defaultValue, setDefaultValue] = useState('');
  const [validationError, setValidationError] = useState(null);
  const editorRef = useRef(null);

  useEffect(() => {
    apiFetch({
      path: '/blockbite/v1/items/get-item/?handle=blockbite-global-css',
    }).then((res: any) => {
      if (has(res, 'status') && res.status === 200 && res.data?.content) {
        setDefaultValue(res.data.content);
      }
    });
  }, [open]);

  function handleEditorDidMount(editor: any, monaco: any) {
    editorRef.current = editor;
    // Extend CSS language configuration to allow `@apply`
    monaco.languages.css.cssDefaults.setOptions({
      validate: true,
      lint: {
        // Disable unknown at-rules validation to avoid flagging @apply
        unknownAtRules: 'ignore',
      },
    });
  }

  function handleEditorValidation(markers: any) {
    if (!markers.length) {
      setValidationError(null);
      return;
    } else {
      const errorsArr: string[] = [];
      markers.forEach((marker: any) => {
        errorsArr.push(marker.message);
      });
      const validationString = errorsArr.join('; ');

      setValidationError(`Validation error: ${validationString}`);
    }
  }

  async function saveCode() {
    if (validationError) {
      setMessage({ status: 'error', value: validationError });
      return;
    }

    setSaving(true);

    const editorValue = editorRef.current.getValue();

    // Extract all the tailwind classes from @apply directives
    const tailwindClassesMatches = editorValue.match(/@apply\s+(.*?);/g) || [];
    const tailwindClasses = tailwindClassesMatches.map((match: any) => {
      // Extract the classes from the match string
      return match.replace(/@apply\s+|;/g, '').trim();
    });

    // Generate the Tailwind CSS
    const tailwindCss = await createTailwind(
      `<div class="${tailwindClasses.join(' ')}"></div>`,
      editorValue
    );

    if (!tailwindCss) {
      setMessage({
        status: 'error',
        value:
          'Failed to generate Tailwind styles. Please check your styles for syntax errors.',
      });
      setSaving(false);
      return;
    }

    // Perform the API fetch to save styles
    apiFetch({
      path: '/blockbite/v1/items/upsert-handle',
      method: 'POST',
      data: {
        handle: 'blockbite-global-css',
        category: 'user-styles',
        css: tailwindCss,
        tailwind: tailwindClasses.join(' '), // Join classes into a single string
        content: editorValue,
      },
    })
      .then((res) => {
        if (has(res, 'status') && res.status === 200) {
          setMessage({
            status: 'success',
            value: 'Styles saved successfully.',
          });
          // Live update global styles
          const settings = wp.data.select('core/editor').getEditorSettings();

          wp.data.dispatch('core/editor').updateEditorSettings({
            ...settings,
            styles: (settings?.styles || []).map((s: any) => {
              if (s.source !== 'blockbite-global-css') {
                return s;
              }

              return {
                ...s,
                css: tailwindCss,
              };
            }),
          });

          setTimeout(() => {
            setOpen(false);
          }, 1000);
        } else {
          setMessage({ status: 'error', value: 'Failed to save styles.' });
        }
      })
      .catch((error) => {
        // Handle any errors that occur during the API request
        console.error('Error saving styles:', error);
        setMessage({
          status: 'error',
          value: 'An error occurred while saving styles.',
        });
      })
      .finally(() => {
        setSaving(false);
      });
  }

  return (
    <Modal defaultOpen={open} onOpenChange={setOpen}>
      <ModalTrigger>
        <Button className="is-primary flex items-center justify-center">
          <span>Styles Editor</span>
        </Button>
      </ModalTrigger>
      <ModalContent className="blockbite--Modal min-h-[640px] sm:max-w-xl">
        <ModalHeader>
          <ModalTitle>Styles Editor</ModalTitle>
        </ModalHeader>
        <p>
          Add custom styles here. This will be applied globally. You can use
          Tailwind's <strong>@apply</strong> directive to apply utility classes.
        </p>
        {message && (
          <Notice
            status={message.status}
            key={message.value}
            onDismiss={() => {
              setMessage('');
            }}
          >
            {message.value}
          </Notice>
        )}
        <div className="border-gray-light my-2 h-full rounded border">
          <Editor
            key={open.toString()}
            className="h-[480px]"
            defaultLanguage="css"
            defaultValue={defaultValue}
            onMount={handleEditorDidMount}
            onChange={() => {
              setValidationError(null);
            }}
            onValidate={handleEditorValidation}
          />
        </div>
        <ModalFooter>
          <ModalClose>
            <Button variant="tertiary">Cancel</Button>
          </ModalClose>
          <Button variant="primary" disabled={saving} onClick={saveCode}>
            Save
          </Button>
        </ModalFooter>
      </ModalContent>
    </Modal>
  );
};
