import React, { useState, useEffect, useCallback, useMemo } from 'react';
import { Avatar, Badge, Box, Button, color, config, Header, IconButton, Input, Menu, MenuItem, PopOut, RectCords, Scroll, Spinner, Switch, Text, toRem } from 'folds';
import { Icon, Icons } from '../../../components/icons';
import { HexColorPicker } from 'react-colorful';
import FocusTrap from 'focus-trap-react';
import { Page, PageContent, PageHeader } from '../../../components/page';
import { PluginTab, PluginMetadata, InstalledPlugin } from './types';
import { SequenceCard } from '../../../components/sequence-card';
import { SettingTile } from '../../../components/setting-tile';
import { SequenceCardStyle } from '../styles.css';
import { pluginMarketplaceManager, pluginRegistry, SettingDefinition } from './PluginAPI';
import { stopPropagation } from '../../../utils/keyboard';
import { fuzzyFilter } from '../../../utils/fuzzy';

/**
 * Renders settings UI for a plugin based on its settings schema
 */
function PluginSettingsRenderer({ pluginId }: { pluginId: string }) {
  const schema = pluginRegistry.getPluginSettingsSchema(pluginId);
  const [, forceUpdate] = useState({});

  if (!schema || Object.keys(schema).length === 0) {
    return (
      <Box padding="300">
        <Text size="T300" priority="300">No settings available for this plugin.</Text>
      </Box>
    );
  }

  const handleChange = (key: string, value: any) => {
    pluginRegistry.setPluginSetting(pluginId, key, value);
    forceUpdate({});
  };

  return (
    <Box direction="Column" gap="300" style={{ padding: config.space.S400 }}>
      {Object.entries(schema).map(([key, def]) => (
        <SettingRenderer
          key={key}
          settingKey={key}
          definition={def}
          value={pluginRegistry.getPluginSetting(pluginId, key)}
          onChange={(value) => handleChange(key, value)}
        />
      ))}
    </Box>
  );
}

/**
 * Renders a single setting based on its type
 */
function SettingRenderer({
  settingKey,
  definition,
  value,
  onChange,
}: {
  settingKey: string;
  definition: SettingDefinition;
  value: any;
  onChange: (value: any) => void;
}) {
  const [colorMenuCords, setColorMenuCords] = useState<RectCords>();
  const [selectMenuCords, setSelectMenuCords] = useState<RectCords>();

  const label = definition.label || settingKey;
  const description = definition.description;

  // Boolean - Switch
  if (definition.type === 'boolean') {
    return (
      <SettingTile
        title={label}
        description={description}
        after={<Switch value={value ?? definition.default ?? false} onChange={onChange} />}
      />
    );
  }

  // String - Input
  if (definition.type === 'string') {
    return (
      <SettingTile title={label} description={description}>
        <Input
          size="400"
          variant="Background"
          value={value ?? definition.default ?? ''}
          onChange={(e) => onChange(e.target.value)}
          placeholder={definition.default}
        />
      </SettingTile>
    );
  }

  // Number - Input
  if (definition.type === 'number') {
    return (
      <SettingTile title={label} description={description}>
        <Input
          size="400"
          variant="Background"
          type="number"
          value={value ?? definition.default ?? 0}
          onChange={(e) => onChange(parseFloat(e.target.value) || 0)}
        />
      </SettingTile>
    );
  }

  // Select - Dropdown
  if (definition.type === 'select' && definition.options) {
    const currentValue = value ?? definition.default ?? definition.options[0]?.value;
    const selectedOption = definition.options.find(opt => opt.value === currentValue);

    return (
      <SettingTile title={label} description={description}>
        <Button
          size="300"
          variant="Primary"
          outlined
          fill="Soft"
          radii="300"
          after={<Icon size="300" src={Icons.ChevronBottom} />}
          onClick={(evt) => setSelectMenuCords(evt.currentTarget.getBoundingClientRect())}
        >
          <Text size="T300">{selectedOption?.label || currentValue}</Text>
        </Button>
        <PopOut
          anchor={selectMenuCords}
          offset={5}
          position="Bottom"
          align="End"
          content={
            <FocusTrap
              focusTrapOptions={{
                initialFocus: false,
                onDeactivate: () => setSelectMenuCords(undefined),
                clickOutsideDeactivates: true,
                escapeDeactivates: stopPropagation,
              }}
            >
              <Menu>
                {definition.options.map((option) => (
                  <MenuItem
                    key={option.value}
                    size="300"
                    after={currentValue === option.value ? <Icon size="100" src={Icons.Check} /> : undefined}
                    radii="300"
                    onClick={() => {
                      onChange(option.value);
                      setSelectMenuCords(undefined);
                    }}
                  >
                    <Text size="T300">{option.label}</Text>
                  </MenuItem>
                ))}
              </Menu>
            </FocusTrap>
          }
        />
      </SettingTile>
    );
  }

  // Color - Color Picker
  if (definition.type === 'color') {
    const currentColor = value ?? definition.default ?? '#000000';

    return (
      <SettingTile title={label} description={description}>
        <Button
          size="400"
          variant="Primary"
          outlined
          fill="Soft"
          radii="300"
          before={
            <Box
              style={{
                width: toRem(20),
                height: toRem(20),
                borderRadius: config.radii.R300,
                backgroundColor: currentColor,
                border: `1px solid ${color.Surface.ContainerLine}`,
              }}
            />
          }
          onClick={(evt) => setColorMenuCords(evt.currentTarget.getBoundingClientRect())}
        >
          <Text size="T300">{currentColor}</Text>
        </Button>
        <PopOut
          anchor={colorMenuCords}
          offset={5}
          position="Bottom"
          align="End"
          content={
            <FocusTrap
              focusTrapOptions={{
                initialFocus: false,
                onDeactivate: () => setColorMenuCords(undefined),
                clickOutsideDeactivates: true,
                escapeDeactivates: stopPropagation,
              }}
            >
              <Box style={{ padding: config.space.S300 }}>
                <HexColorPicker color={currentColor} onChange={onChange} />
              </Box>
            </FocusTrap>
          }
        />
      </SettingTile>
    );
  }

  return null;
}

type PluginsProps = {
  requestClose: () => void;
};

export function Plugins({ requestClose }: PluginsProps) {
  const [activeTab, setActiveTab] = useState<PluginTab>(PluginTab.Marketplace);
  const [marketplacePlugins, setMarketplacePlugins] = useState<PluginMetadata[]>([]);
  const [installedPlugins, setInstalledPlugins] = useState<InstalledPlugin[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const [expandedSettings, setExpandedSettings] = useState<string | null>(null);

  const refreshInstalledPlugins = useCallback(async () => {
    try {
      setInstalledPlugins(await pluginMarketplaceManager.listInstalledPlugins());
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to list installed plugins');
      console.error('Failed to list installed plugins:', err);
    }
  }, []);

  const fetchMarketplacePlugins = useCallback(async () => {
    setLoading(true);
    setError(null);

    try {
      setMarketplacePlugins(await pluginMarketplaceManager.fetchMarketplacePlugins());
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to fetch plugins');
      console.error('Error fetching marketplace plugins:', err);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    if (activeTab === PluginTab.Marketplace) {
      fetchMarketplacePlugins();
    }
  }, [activeTab, fetchMarketplacePlugins]);

  useEffect(() => {
    refreshInstalledPlugins();
  }, [refreshInstalledPlugins]);

  const handleInstall = useCallback(
    async (plugin: PluginMetadata) => {
      try {
        setLoading(true);
        setError(null);
        await pluginMarketplaceManager.installPlugin(plugin);
        await refreshInstalledPlugins();
      } catch (err) {
        console.error('Failed to install plugin:', err);
        setError(err instanceof Error ? err.message : 'Failed to install plugin');
      } finally {
        setLoading(false);
      }
    },
    [refreshInstalledPlugins]
  );

  const handleUninstall = useCallback(
    async (pluginId: string) => {
      try {
        setError(null);
        await pluginMarketplaceManager.uninstallPlugin(pluginId);
        await refreshInstalledPlugins();
      } catch (err) {
        console.error('Failed to uninstall plugin:', err);
        setError(err instanceof Error ? err.message : 'Failed to uninstall plugin');
      }
    },
    [refreshInstalledPlugins]
  );

  const handleToggleEnabled = useCallback(
    async (pluginId: string) => {
      const plugin = installedPlugins.find((p) => p.id === pluginId);
      if (!plugin) return;

      const newEnabledState = !plugin.enabled;

      try {
        setError(null);
        await pluginMarketplaceManager.setPluginEnabled(pluginId, newEnabledState);
        await refreshInstalledPlugins();
        if (newEnabledState) {
          console.log(`[Plugins] Plugin ${pluginId} enabled. Restart app to load it.`);
        }
      } catch (err) {
        console.error(`Failed to toggle plugin ${pluginId}:`, err);
        setError(err instanceof Error ? err.message : 'Failed to update plugin state');
      }
    },
    [installedPlugins, refreshInstalledPlugins]
  );

  const isPluginInstalled = useCallback(
    (pluginId: string) => installedPlugins.some((p) => p.id === pluginId),
    [installedPlugins]
  );

  const PluginAvatar = ({ thumbnail, name }: { thumbnail: string; name: string }) => {
    const [imageError, setImageError] = useState(false);

    return (
      <Avatar size="500" radii="400">
        {!imageError ? (
          <img
            src={thumbnail}
            alt={name}
            style={{
              width: '100%',
              height: '100%',
              objectFit: 'cover',
              borderRadius: 'inherit',
            }}
            onError={() => setImageError(true)}
          />
        ) : (
          <Box
            justifyContent="Center"
            alignItems="Center"
            style={{
              width: '100%',
              height: '100%',
              background: `linear-gradient(135deg, ${color.Secondary.Container} 0%, ${color.Primary.Container} 100%)`,
              borderRadius: 'inherit',
            }}
          >
            <Text size="H3" priority="300" style={{ fontWeight: 600 }}>
              {name.charAt(0).toUpperCase()}
            </Text>
          </Box>
        )}
      </Avatar>
    );
  };

  const filteredMarketplacePlugins = useMemo(() => {
    if (!searchQuery.trim()) return marketplacePlugins;
    return fuzzyFilter(marketplacePlugins, searchQuery, (plugin) => [
      plugin.name,
      plugin.description,
      plugin.author,
      ...plugin.tags,
    ]).map(({ item }) => item);
  }, [marketplacePlugins, searchQuery]);

  const filteredInstalledPlugins = useMemo(() => {
    if (!searchQuery.trim()) return installedPlugins;
    return fuzzyFilter(installedPlugins, searchQuery, (plugin) => [
      plugin.name,
      plugin.description,
      plugin.author,
    ]).map(({ item }) => item);
  }, [installedPlugins, searchQuery]);

  return (
    <Page>
      <PageHeader>
        <Box grow="Yes" alignItems="Center" gap="200">
          <Header size="H3" className="truncate">
            Plugins
          </Header>
        </Box>
        <Box shrink="No" gap="200">
          <Button variant="Background" size="300" onClick={requestClose}>
            <Text size="B300">Close</Text>
          </Button>
        </Box>
      </PageHeader>
      <Box shrink="No" style={{ padding: `0 ${config.space.S400}` }} direction="Column" gap="300">
        <Box gap="200">
          <Badge
            style={{ cursor: 'pointer' }}
            as="button"
            variant="Secondary"
            fill={activeTab === PluginTab.Marketplace ? 'Solid' : 'None'}
            size="500"
            onClick={() => setActiveTab(PluginTab.Marketplace)}
          >
            <Text as="span" size="L400">
              Marketplace
            </Text>
          </Badge>
          <Badge
            style={{ cursor: 'pointer' }}
            as="button"
            variant="Secondary"
            fill={activeTab === PluginTab.Installed ? 'Solid' : 'None'}
            size="500"
            onClick={() => setActiveTab(PluginTab.Installed)}
          >
            <Text as="span" size="L400">
              Installed
            </Text>
          </Badge>
        </Box>
        <Input
          variant="Background"
          size="400"
          placeholder="Search plugins..."
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          before={<Icon size="100" src={Icons.Search} />}
          after={
            searchQuery && (
              <IconButton
                size="300"
                variant="SurfaceLow"
                radii="300"
                onClick={() => setSearchQuery('')}
              >
                <Icon size="50" src={Icons.Cross} filled />
              </IconButton>
            )
          }
        />
      </Box>
      <Box grow="Yes" direction="Column">
        <Scroll variant="Background" visibility="Hover" hideTrack size="300">
          <PageContent>
            <SequenceCard
              className={SequenceCardStyle}
              variant="SurfaceVariant"
              direction="Column"
              gap="400"
            >
              {activeTab === PluginTab.Marketplace && (
                <Box direction="Column" gap="400">
                  {loading && (
                    <Box justifyContent="Center" alignItems="Center" style={{ padding: toRem(32) }}>
                      <Spinner variant="Secondary" size="400" />
                    </Box>
                  )}
                  {error && (
                    <Box direction="Column" gap="200" style={{ padding: toRem(16) }}>
                      <Text size="T400" priority="300">
                        Error: {error}
                      </Text>
                      <Button onClick={fetchMarketplacePlugins} size="300" variant="Primary">
                        <Text size="B300">Retry</Text>
                      </Button>
                    </Box>
                  )}
                  {!loading && !error && filteredMarketplacePlugins.length === 0 && (
                    <Box justifyContent="Center" style={{ padding: toRem(32) }}>
                      <Text size="T400" priority="300">
                        {searchQuery ? 'No plugins found matching your search' : 'No plugins available'}
                      </Text>
                    </Box>
                  )}
                  {!loading &&
                    !error &&
                    filteredMarketplacePlugins.map((plugin) => (
                      <Box
                        key={plugin.id}
                        style={{
                          padding: config.space.S500,
                          background: color.Surface.Container,
                          borderRadius: config.radii.R400,
                          border: `1px solid ${color.Surface.ContainerLine}`,
                          transition: 'all 0.2s ease',
                        }}
                        onMouseEnter={(e) => {
                          e.currentTarget.style.transform = 'translateY(-2px)';
                          e.currentTarget.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';
                        }}
                        onMouseLeave={(e) => {
                          e.currentTarget.style.transform = 'translateY(0)';
                          e.currentTarget.style.boxShadow = 'none';
                        }}
                      >
                        <Box gap="500" alignItems="Start">
                          <Box shrink="No">
                            <PluginAvatar thumbnail={plugin.thumbnail} name={plugin.name} />
                          </Box>
                          <Box grow="Yes" direction="Column" gap="200">
                            <Box direction="Column" gap="100">
                              <Text size="H5">{plugin.name}</Text>
                              <Box gap="200" alignItems="Center">
                                <Text size="T200" priority="400">
                                  by {plugin.author}
                                </Text>
                                <Text size="T200" priority="400">•</Text>
                                <Text size="T200" priority="400">
                                  v{plugin.version}
                                </Text>
                              </Box>
                            </Box>
                            <Text size="T300" priority="300">
                              {plugin.description}
                            </Text>
                            {plugin.tags.length > 0 && (
                              <Box gap="100" wrap="Wrap">
                                {plugin.tags.map((tag) => (
                                  <Badge key={tag} size="300" variant="Secondary" fill="Soft">
                                    <Text size="L400">{tag}</Text>
                                  </Badge>
                                ))}
                              </Box>
                            )}
                          </Box>
                          <Box shrink="No">
                            <Button
                              variant={isPluginInstalled(plugin.id) ? 'Success' : 'Primary'}
                              size="400"
                              onClick={() => handleInstall(plugin)}
                              disabled={isPluginInstalled(plugin.id)}
                            >
                              <Text size="B400">
                                {isPluginInstalled(plugin.id) ? 'Installed' : 'Install'}
                              </Text>
                            </Button>
                          </Box>
                        </Box>
                      </Box>
                    ))}
                </Box>
              )}
              {activeTab === PluginTab.Installed && (
                <Box direction="Column" gap="400">
                  {filteredInstalledPlugins.length === 0 && (
                    <Box justifyContent="Center" style={{ padding: toRem(32) }}>
                      <Text size="T400" priority="300">
                        {searchQuery ? 'No installed plugins found matching your search' : 'No plugins installed'}
                      </Text>
                    </Box>
                  )}
                  {filteredInstalledPlugins.map((plugin) => {
                    const hasSettings = pluginRegistry.getPluginSettingsSchema(plugin.id) && 
                      Object.keys(pluginRegistry.getPluginSettingsSchema(plugin.id)!).length > 0;
                    const settingsExpanded = expandedSettings === plugin.id;

                    return (
                    <Box
                      key={plugin.id}
                      direction="Column"
                      style={{
                        background: color.Surface.Container,
                        borderRadius: config.radii.R400,
                        border: `1px solid ${color.Surface.ContainerLine}`,
                        transition: 'all 0.2s ease',
                      }}
                    >
                      <Box
                        style={{
                          padding: config.space.S500,
                        }}
                        onMouseEnter={(e) => {
                          e.currentTarget.parentElement!.style.transform = 'translateY(-2px)';
                          e.currentTarget.parentElement!.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';
                        }}
                        onMouseLeave={(e) => {
                          e.currentTarget.parentElement!.style.transform = 'translateY(0)';
                          e.currentTarget.parentElement!.style.boxShadow = 'none';
                        }}
                      >
                      <Box gap="500" alignItems="Start">
                        <Box shrink="No">
                          <PluginAvatar thumbnail={plugin.thumbnail} name={plugin.name} />
                        </Box>
                        <Box grow="Yes" direction="Column" gap="200">
                          <Box direction="Column" gap="100">
                            <Text size="H5">{plugin.name}</Text>
                            <Box gap="200" alignItems="Center">
                              <Text size="T200" priority="400">
                                by {plugin.author}
                              </Text>
                              <Text size="T200" priority="400">•</Text>
                              <Text size="T200" priority="400">
                                v{plugin.version}
                              </Text>
                            </Box>
                          </Box>
                          <Text size="T300" priority="300">
                            {plugin.description}
                          </Text>
                          <Box gap="100" wrap="Wrap">
                            <Badge
                              size="300"
                              variant={plugin.enabled ? 'Success' : 'Secondary'}
                              fill="Soft"
                            >
                              <Text size="L400">{plugin.enabled ? 'Enabled' : 'Disabled'}</Text>
                            </Badge>
                          </Box>
                        </Box>
                        <Box shrink="No" direction="Column" gap="200">
                          {hasSettings && (
                            <Button
                              variant="Secondary"
                              fill="Soft"
                              size="400"
                              before={<Icon size="200" src={Icons.Setting} />}
                              after={<Icon size="200" src={settingsExpanded ? Icons.ChevronTop : Icons.ChevronBottom} />}
                              onClick={() => setExpandedSettings(settingsExpanded ? null : plugin.id)}
                            >
                              <Text size="B400">Settings</Text>
                            </Button>
                          )}
                          <Button
                            variant="Secondary"
                            size="400"
                            onClick={() => handleToggleEnabled(plugin.id)}
                          >
                            <Text size="B400">{plugin.enabled ? 'Disable' : 'Enable'}</Text>
                          </Button>
                          <Button
                            variant="Critical"
                            fill="None"
                            size="400"
                            onClick={() => handleUninstall(plugin.id)}
                          >
                            <Text size="B400">Uninstall</Text>
                          </Button>
                        </Box>
                      </Box>
                      </Box>
                      {hasSettings && settingsExpanded && (
                        <Box
                          direction="Column"
                          style={{
                            borderTop: `1px solid ${color.Surface.ContainerLine}`,
                            background: color.Surface.ContainerLowest,
                          }}
                        >
                          <PluginSettingsRenderer pluginId={plugin.id} />
                        </Box>
                      )}
                    </Box>
                    );
                  })}
                </Box>
              )}
            </SequenceCard>
          </PageContent>
        </Scroll>
      </Box>
    </Page>
  );
}
