import * as React from 'react';
import { Messenger, messageHandler } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { Settings } from '../../models/Settings';
import { Status } from '../../models/Status';
import { Step } from './Step';
import { useMemo, useState } from 'react';
import { Menu } from '@headlessui/react';
import { MenuItem } from '../Menu';
import { Framework, StaticFolder, Template } from '../../../models';
import { ChevronDownIcon } from '@heroicons/react/24/outline';
import { FrameworkDetectors } from '../../../constants/FrameworkDetectors';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../../localization';
import { SelectItem } from './SelectItem';
import { GeneralCommands, SETTING_GIT_ENABLED, Templates } from '../../../constants';
import { TemplateItem } from './TemplateItem';
import { Spinner } from '../Common/Spinner';
import { AstroContentTypes } from '../Configuration/Astro/AstroContentTypes';
import { ContentFolders } from '../Configuration/Common/ContentFolders';
import { VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react';

export interface IStepsToGetStartedProps {
  settings: Settings;
}

export const StepsToGetStarted: React.FunctionComponent<IStepsToGetStartedProps> = ({
  settings
}: React.PropsWithChildren<IStepsToGetStartedProps>) => {
  const [loading, setLoading] = useState<boolean>(false);
  const [framework, setFramework] = useState<string | null>(null);
  const [taxImported, setTaxImported] = useState<boolean>(false);
  const [isGitEnabled, setIsGitEnabled] = useState<boolean>(false);
  const [isGitRepo, setIsGitRepo] = useState<boolean>(false);
  const [templates, setTemplates] = useState<Template[]>([]);
  const [astroCollectionsStatus, setAstroCollectionsStatus] = useState<Status>(Status.Optional);

  const frameworks: Framework[] = FrameworkDetectors.map((detector: any) => detector.framework);

  const setFrameworkAndSendMessage = (framework: string) => {
    setFramework(framework);
    Messenger.send(DashboardMessage.setFramework, framework);
  };

  const addAssetFolder = (folder: string | StaticFolder) => {
    Messenger.send(DashboardMessage.addAssetsFolder, folder);
  }

  const triggerTemplate = (template: Template) => {
    setLoading(true);
    messageHandler.request<boolean>(DashboardMessage.triggerTemplate, template).then((result) => {
      setLoading(false);
      if (result) {
        reload();
      }
    });
  }

  const showNotification = () => {
    Messenger.send(DashboardMessage.openConfig);
  };

  const reload = () => {
    const crntState: any = Messenger.getState() || {};

    Messenger.setState({
      ...crntState,
      isWelcomeConfiguring: false
    });

    Messenger.send(DashboardMessage.reload);
  };

  const importTaxonomy = () => {
    Messenger.send(DashboardMessage.importTaxonomy);
    setTaxImported(true);
  };

  const updateSetting = (name: string, value: any) => {
    setIsGitEnabled(value);
    Messenger.send(DashboardMessage.updateSetting, {
      name,
      value,
      global: true
    });
  }

  const crntTemplates = useMemo(() => {
    if (!templates || templates.length === 0 || !settings.crntFramework) {
      return [];
    }

    return templates.filter((t) => t.type === settings.crntFramework);
  }, [templates, settings.crntFramework])

  const steps = useMemo(() => (
    [
      {
        id: `welcome-init`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedInitializeProjectName),
        description: <>{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedInitializeProjectDescription)}</>,
        show: true,
        status: settings.initialized ? Status.Completed : Status.NotStarted,
        onClick: settings.initialized
          ? undefined
          : () => {
            Messenger.send(DashboardMessage.initializeProject);
          }
      },
      {
        id: `welcome-framework`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedFrameworkName),
        description: (
          <div>
            <div>
              {l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedFrameworkDescription)}
            </div>

            <Menu as="div" className="relative inline-block text-left mt-4">
              <div>
                <Menu.Button className={`group flex justify-center p-2 rounded-md border text-[var(--vscode-tab-inactiveForeground)] hover:text-[var(--vscode-tab-activeForeground)]`}>
                  {framework ? framework : l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedFrameworkSelect)}
                  <ChevronDownIcon
                    className={`flex-shrink-0 -mr-1 ml-1 h-5 w-5`}
                    aria-hidden="true"
                  />
                </Menu.Button>
              </div>

              <Menu.Items
                className={`w-40 origin-top-left absolute left-0 z-10 mt-2 rounded-md shadow-2xl ring-1 ring-opacity-5 focus:outline-none text-sm max-h-96 overflow-auto bg-[var(--vscode-sideBar-background)] ring-[var(--frontmatter-border)]`}
              >
                <div className="py-1">
                  <MenuItem
                    title={l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedFrameworkSelectOther)}
                    value={`other`}
                    isCurrent={!framework}
                    onClick={(value: string) => setFrameworkAndSendMessage(value)}
                  />

                  <hr className={`border-[var(--frontmatter-border)]`} />

                  {frameworks.map((f) => (
                    <MenuItem
                      key={f.name}
                      title={f.name}
                      value={f.name}
                      isCurrent={f.name === framework}
                      onClick={(value: string) => setFrameworkAndSendMessage(value)}
                    />
                  ))}
                </div>
              </Menu.Items>
            </Menu>
          </div>
        ),
        show: true,
        status: settings.crntFramework ? Status.Completed : Status.NotStarted,
        onClick: undefined
      },
      {
        id: `welcome-template`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTemplateName),
        description: (
          <div className=''>
            <div className="text-sm">{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTemplateDescription)}</div>
            <div className="mt-4 grid grid-cols-2 lg:grid-cols-3 gap-x-4 gap-y-4 w-full">
              {
                crntTemplates && (crntTemplates || []).map(template => (
                  <TemplateItem
                    key={template.name.toLowerCase().replace(/ /g, '-')}
                    title={template.name}
                    author={template.author}
                    version={template.version}
                    description={template.description}
                    buttonTitle={template.name}
                    onClick={() => triggerTemplate(template)} />
                ))
              }
            </div>

            <p className='mt-4 text-[var(--vscode-editorWarning-foreground)]'>
              <b>{l10n.t(LocalizationKey.commonImportant)}</b>: {l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTemplateWarning)}</p>
          </div>
        ),
        show: (crntTemplates || []).length > 0,
        status: Status.Optional,
      },
      {
        id: `astro-content-types`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAstroContentTypesName),
        description: (
          <AstroContentTypes
            settings={settings}
            triggerLoading={(isLoading) => setLoading(isLoading)}
            setStatus={(status) => setAstroCollectionsStatus(status)} />
        ),
        show: settings.crntFramework === 'astro',
        status: astroCollectionsStatus
      },
      {
        id: `welcome-content-folders`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedContentFoldersName),
        description: (
          <ContentFolders
            settings={settings}
            triggerLoading={(isLoading) => setLoading(isLoading)} />
        ),
        show: true,
        status:
          settings.contentFolders && settings.contentFolders.length > 0
            ? Status.Completed
            : Status.NotStarted
      },
      {
        id: `welcome-assets`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderName),
        description: (
          <div className='mt-1'>
            <div className="text-sm">{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderDescription)}</div>
            <div className="mt-1 space-y-1">
              <SelectItem
                title={l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderPublicTitle)}
                buttonTitle={l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderPublicTitle)}
                isSelected={settings.staticFolder === "public"}
                onClick={() => addAssetFolder(`public`)} />

              <SelectItem
                title={l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderAssetsTitle)}
                buttonTitle={l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderAssetsTitle)}
                isSelected={settings.staticFolder === "src/assets"}
                onClick={() => addAssetFolder({
                  "path": "src/assets",
                  "relative": true
                })} />

              <p className='text-sm'>
                <b>{l10n.t(LocalizationKey.commonInformation)}</b>: {l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedAssetsFolderOtherDescription)}</p>
            </div>
          </div>
        ),
        show: settings.crntFramework === 'astro' || framework === 'astro',
        status: settings.initialized && settings.staticFolder && settings.staticFolder !== "/" ? Status.Completed : Status.NotStarted,
      },
      {
        id: `welcome-git`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitName),
        description: (
          <div className='mt-1'>
            <VSCodeCheckbox
              onChange={(e: React.ChangeEvent<HTMLInputElement>) => updateSetting(SETTING_GIT_ENABLED, e.target.checked)}
              checked={isGitEnabled}>
              {l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedGitDescription)}
            </VSCodeCheckbox>
          </div>
        ),
        show: isGitRepo,
        status: settings.git.actions ? Status.Completed : Status.NotStarted
      },
      {
        id: `welcome-import`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTagsName),
        description: <>{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedTagsDescription)}</>,
        show: true,
        status: taxImported ? Status.Completed : Status.NotStarted,
        onClick:
          settings.contentFolders && settings.contentFolders.length > 0 ? importTaxonomy : undefined
      },
      {
        id: `welcome-show-dashboard`,
        name: l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedShowDashboardName),
        description: <>{l10n.t(LocalizationKey.dashboardStepsStepsToGetStartedShowDashboardDescription)}</>,
        show: true,
        status:
          settings.initialized && settings.contentFolders && settings.contentFolders.length > 0
            ? Status.Active
            : Status.NotStarted,
        onClick:
          settings.initialized && settings.contentFolders && settings.contentFolders.length > 0
            ? () => {
              showNotification();
              reload();
            }
            : undefined
      }
    ]
  ), [settings, framework, taxImported, templates, astroCollectionsStatus, isGitRepo]);

  React.useEffect(() => {
    if (settings.crntFramework || settings.framework?.name) {
      setFramework(settings.crntFramework || settings.framework?.name || null);
    }
  }, [settings.crntFramework, settings.framework]);

  React.useEffect(() => {
    messageHandler.request<boolean>(GeneralCommands.toVSCode.gitIsRepo).then((result) => {
      setIsGitRepo(result);
    });

    setIsGitEnabled(settings.git.actions);
  }, [settings.git.actions]);

  React.useEffect(() => {
    const fetchTemplates = async () => {
      try {
        const response = await fetch(Templates.url);

        if (response.ok) {
          const data = await response.json();
          setTemplates(data);
        }
      } catch (e) {
        setTemplates([]);
      }
    };

    fetchTemplates();
  }, []);

  return (
    <nav aria-label="Progress">
      {
        loading && (
          <Spinner />
        )
      }
      <ol role="list">
        {steps.map((step, stepIdx) => (
          step.show && (
            <li
              key={step.id}
              className={`${stepIdx !== steps.length - 1 ? 'pb-10' : ''} relative`}
              data-test={step.id}
            >
              <Step
                name={step.name}
                description={step.description}
                status={step.status}
                showLine={stepIdx !== steps.length - 1}
                onClick={step.onClick}
              />
            </li>
          )
        ))}
      </ol>
    </nav>
  );
};
