import { ChainType } from "@/chainFactory";
import { Button } from "@/components/ui/button";
import { HelpTooltip } from "@/components/ui/help-tooltip";
import { Input } from "@/components/ui/input";
import { getModelDisplayWithIcons } from "@/components/ui/model-display";
import { SettingItem } from "@/components/ui/setting-item";
import { Textarea } from "@/components/ui/textarea";
import { DEFAULT_OPEN_AREA, DEFAULT_VIM_NAVIGATION, PLUS_UTM_MEDIUMS, SEND_SHORTCUT } from "@/constants";
import { useTab } from "@/contexts/TabContext";
import { cn } from "@/lib/utils";
import { createPlusPageUrl } from "@/plusUtils";
import { getModelKeyFromModel, updateSetting, useSettingsValue } from "@/settings/model";
import { PlusSettings } from "@/settings/v2/components/PlusSettings";
import { checkModelApiKey, formatDateTime } from "@/utils";
import { isSortStrategy } from "@/utils/recentUsageManager";
import { buildNavMappingText, parseNavMappings } from "@/utils/vimKeyboardNavigation";
import { Key, Loader2 } from "lucide-react";
import { Notice } from "obsidian";
import React, { useState, useEffect } from "react";
import { ApiKeyDialog } from "./ApiKeyDialog";

const ChainType2Label: Record<ChainType, string> = {
  [ChainType.LLM_CHAIN]: "Chat",
  [ChainType.VAULT_QA_CHAIN]: "Vault QA (Basic)",
  [ChainType.COPILOT_PLUS_CHAIN]: "Copilot Plus",
  [ChainType.PROJECT_CHAIN]: "Projects (alpha)",
};

/**
 * Vim key mappings textarea component.
 * Displays when Vim navigation is enabled.
 */
const VimKeyMappings: React.FC = () => {
  const settings = useSettingsValue();
  const [mappingText, setMappingText] = useState(() => buildNavMappingText(settings.vimNavigation));
  const [error, setError] = useState<string | null>(null);

  // Sync mappingText when settings change externally
  const { scrollUpKey, scrollDownKey, focusInputKey, enabled } = settings.vimNavigation;
  useEffect(() => {
    setMappingText(buildNavMappingText({ scrollUpKey, scrollDownKey, focusInputKey, enabled }));
  }, [scrollUpKey, scrollDownKey, focusInputKey, enabled]);

  /**
   * Validates and persists on every change.
   * Saves immediately when valid to prevent data loss if settings view closes.
   */
  const handleMappingChange = (value: string) => {
    setMappingText(value);

    const result = parseNavMappings(value);
    if (result.error) {
      setError(result.error);
      return;
    }

    setError(null);
    updateSetting("vimNavigation", {
      ...settings.vimNavigation,
      scrollUpKey: result.settings!.scrollUp,
      scrollDownKey: result.settings!.scrollDown,
      focusInputKey: result.settings!.focusInput,
    });
  };

  const handleReset = () => {
    const defaultText = buildNavMappingText(DEFAULT_VIM_NAVIGATION);
    setMappingText(defaultText);
    setError(null);
    updateSetting("vimNavigation", {
      ...settings.vimNavigation,
      scrollUpKey: DEFAULT_VIM_NAVIGATION.scrollUpKey,
      scrollDownKey: DEFAULT_VIM_NAVIGATION.scrollDownKey,
      focusInputKey: DEFAULT_VIM_NAVIGATION.focusInputKey,
    });
  };

  return (
    <div className="tw-ml-4 tw-border-l tw-border-border tw-pl-4">
      <SettingItem
        type="custom"
        title="Key Mappings"
        description={
          <div className="tw-space-y-1">
            <div>Format: map &lt;key&gt; &lt;action&gt; (one per line)</div>
            <div className="tw-text-xs tw-text-muted">
              Actions: scrollUp, scrollDown, focusInput
            </div>
          </div>
        }
      >
        <div className="tw-flex tw-flex-col tw-gap-2">
          <Textarea
            value={mappingText}
            onChange={(e) => handleMappingChange(e.target.value)}
            className="tw-min-h-[80px] tw-w-full tw-font-mono tw-text-sm sm:tw-w-[240px]"
            rows={3}
          />
          {error && <div className="tw-text-xs tw-text-error">{error}</div>}
          <Button variant="ghost" size="sm" onClick={handleReset} className="tw-w-fit">
            Reset to defaults
          </Button>
        </div>
      </SettingItem>
    </div>
  );
};

export const BasicSettings: React.FC = () => {
  const settings = useSettingsValue();
  const { setSelectedTab } = useTab();
  const [isChecking, setIsChecking] = useState(false);
  const [conversationNoteName, setConversationNoteName] = useState(
    settings.defaultConversationNoteName || "{$date}_{$time}__{$topic}"
  );

  const applyCustomNoteFormat = () => {
    setIsChecking(true);

    try {
      // Check required variables
      const format = conversationNoteName || "{$date}_{$time}__{$topic}";
      const requiredVars = ["{$date}", "{$time}", "{$topic}"];
      const missingVars = requiredVars.filter((v) => !format.includes(v));

      if (missingVars.length > 0) {
        new Notice(`Error: Missing required variables: ${missingVars.join(", ")}`, 4000);
        return;
      }

      // Check illegal characters (excluding variable placeholders)
      const illegalChars = /[\\/:*?"<>|]/;
      const formatWithoutVars = format
        .replace(/\{\$date}/g, "")
        .replace(/\{\$time}/g, "")
        .replace(/\{\$topic}/g, "");

      if (illegalChars.test(formatWithoutVars)) {
        new Notice(`Error: Format contains illegal characters (\\/:*?"<>|)`, 4000);
        return;
      }

      // Generate example filename
      const { fileName: timestampFileName } = formatDateTime(new Date());
      const firstTenWords = "test topic name";

      // Create example filename
      const customFileName = format
        .replace("{$topic}", firstTenWords.slice(0, 100).replace(/\s+/g, "_"))
        .replace("{$date}", timestampFileName.split("_")[0])
        .replace("{$time}", timestampFileName.split("_")[1]);

      // Save settings
      updateSetting("defaultConversationNoteName", format);
      setConversationNoteName(format);
      new Notice(`Format applied successfully! Example: ${customFileName}`, 4000);
    } catch (error) {
      new Notice(`Error applying format: ${error.message}`, 4000);
    } finally {
      setIsChecking(false);
    }
  };

  const defaultModelActivated = !!settings.activeModels.find(
    (m) => m.enabled && getModelKeyFromModel(m) === settings.defaultModelKey
  );
  const enableActivatedModels = settings.activeModels
    .filter((m) => m.enabled)
    .map((model) => ({
      label: getModelDisplayWithIcons(model),
      value: getModelKeyFromModel(model),
    }));

  return (
    <div className="tw-space-y-4">
      <PlusSettings />

      {/* General Section */}
      <section>
        <div className="tw-mb-3 tw-text-xl tw-font-bold">General</div>
        <div className="tw-space-y-4">
          <div className="tw-space-y-4">
            {/* API Key Section */}
            <SettingItem
              type="custom"
              title="API Keys"
              description={
                <div className="tw-flex tw-items-center tw-gap-1.5">
                  <span className="tw-leading-none">
                    Configure API keys for different AI providers
                  </span>
                  <HelpTooltip
                    content={
                      <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2 tw-py-4">
                        <div className="tw-text-sm tw-font-medium tw-text-accent">
                          API key required for chat and QA features
                        </div>
                        <div className="tw-text-xs tw-text-muted">
                          To enable chat and QA functionality, please provide an API key from your
                          selected provider.
                        </div>
                      </div>
                    }
                  />
                </div>
              }
            >
              <Button
                onClick={() => {
                  new ApiKeyDialog(app, () => setSelectedTab("model")).open();
                }}
                variant="secondary"
                className="tw-flex tw-w-full tw-items-center tw-justify-center tw-gap-2 sm:tw-w-auto sm:tw-justify-start"
              >
                Set Keys
                <Key className="tw-size-4" />
              </Button>
            </SettingItem>
          </div>
          <SettingItem
            type="select"
            title="Default Chat Model"
            description={
              <div className="tw-flex tw-items-center tw-gap-1.5">
                <span className="tw-leading-none">Select the Chat model to use</span>
                <HelpTooltip
                  content={
                    <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2 tw-py-4">
                      <div className="tw-text-sm tw-font-medium tw-text-accent">
                        Default model is OpenRouter Gemini 2.5 Flash
                      </div>
                      <div className="tw-text-xs tw-text-muted">
                        Set your OpenRouter API key in &apos;API keys&apos; to use this model, or
                        select a different model from another provider.
                      </div>
                    </div>
                  }
                />
              </div>
            }
            value={defaultModelActivated ? settings.defaultModelKey : "Select Model"}
            onChange={(value) => {
              const selectedModel = settings.activeModels.find(
                (m) => m.enabled && getModelKeyFromModel(m) === value
              );
              if (!selectedModel) return;

              const { hasApiKey, errorNotice } = checkModelApiKey(selectedModel, settings);
              if (!hasApiKey && errorNotice) {
                // Keep selection allowed; error will surface in chat on send
              }
              updateSetting("defaultModelKey", value);
            }}
            options={
              defaultModelActivated
                ? enableActivatedModels
                : [{ label: "Select Model", value: "Select Model" }, ...enableActivatedModels]
            }
            placeholder="Model"
          />

          {/* Basic Configuration Group */}
          <SettingItem
            type="select"
            title="Default Mode"
            description={
              <div className="tw-flex tw-items-center tw-gap-1.5">
                <span className="tw-leading-none">Select the default chat mode</span>
                <HelpTooltip
                  content={
                    <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2">
                      <ul className="tw-pl-4 tw-text-sm tw-text-muted">
                        <li>
                          <strong>Chat:</strong> Regular chat mode for general conversations and
                          tasks. <i>Free to use with your own API key.</i>
                        </li>
                        <li>
                          <strong>Vault QA (Basic):</strong> Ask questions about your vault content
                          with semantic search. <i>Free to use with your own API key.</i>
                        </li>
                        <li>
                          <strong>Copilot Plus:</strong> Covers all features of the 2 free modes,
                          plus advanced paid features including chat context menu, advanced search,
                          AI agents, and more. Check out{" "}
                          <a
                            href={createPlusPageUrl(PLUS_UTM_MEDIUMS.MODE_SELECT_TOOLTIP)}
                            target="_blank"
                            rel="noopener noreferrer"
                            className="tw-text-accent hover:tw-text-accent-hover"
                          >
                            obsidiancopilot.com
                          </a>{" "}
                          for more details.
                        </li>
                      </ul>
                    </div>
                  }
                />
              </div>
            }
            value={settings.defaultChainType}
            onChange={(value) => updateSetting("defaultChainType", value as ChainType)}
            options={Object.entries(ChainType2Label).map(([key, value]) => ({
              label: value,
              value: key,
            }))}
          />

          <SettingItem
            type="select"
            title="Open Plugin In"
            description="Choose where to open the plugin"
            value={settings.defaultOpenArea}
            onChange={(value) => updateSetting("defaultOpenArea", value as DEFAULT_OPEN_AREA)}
            options={[
              { label: "Sidebar View", value: DEFAULT_OPEN_AREA.VIEW },
              { label: "Editor", value: DEFAULT_OPEN_AREA.EDITOR },
            ]}
          />

          <SettingItem
            type="select"
            title="Send Shortcut"
            description={
              <div className="tw-flex tw-items-center tw-gap-1.5">
                <span className="tw-leading-none">Choose keyboard shortcut to send messages</span>
                <HelpTooltip
                  content={
                    <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2 tw-py-4">
                      <div className="tw-text-sm tw-font-medium tw-text-accent">
                        Shortcut not working?
                      </div>
                      <div className="tw-text-xs tw-text-muted">
                        If your selected shortcut doesn&#39;t work, check
                        <strong> Obsidian&#39;s Settings → Hotkeys</strong> to see if another
                        command is using the same key combination. <br />
                        You may need to remove or change the conflicting hotkey first.
                      </div>
                    </div>
                  }
                />
              </div>
            }
            value={settings.defaultSendShortcut}
            onChange={(value) => updateSetting("defaultSendShortcut", value as SEND_SHORTCUT)}
            options={[
              { label: "Enter", value: SEND_SHORTCUT.ENTER },
              { label: "Shift + Enter", value: SEND_SHORTCUT.SHIFT_ENTER },
            ]}
          />

          {/* Vim Navigation */}
          <SettingItem
            type="switch"
            title="Vim-style Navigation"
            description={
              <div className="tw-flex tw-items-center tw-gap-1.5">
                <span className="tw-leading-none">
                  Navigate chat messages using keyboard shortcuts
                </span>
                <HelpTooltip
                  content={
                    <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2 tw-py-4">
                      <div className="tw-text-sm tw-font-medium tw-text-accent">
                        Vim-style keyboard navigation
                      </div>
                      <div className="tw-text-xs tw-text-muted">
                        When enabled, the messages area becomes focusable. Use configured keys to
                        scroll messages, focus input, and Escape to return to messages from input.
                      </div>
                    </div>
                  }
                />
              </div>
            }
            checked={settings.vimNavigation.enabled}
            onCheckedChange={(checked) => {
              updateSetting("vimNavigation", {
                ...settings.vimNavigation,
                enabled: checked,
              });
            }}
          />

          {settings.vimNavigation.enabled && <VimKeyMappings />}

          <SettingItem
            type="switch"
            title="Auto-Add Active Content to Context"
            description="Automatically add the active note or Web Viewer tab (Desktop only) to chat context when sending messages."
            checked={settings.autoAddActiveContentToContext}
            onCheckedChange={(checked) => {
              updateSetting("autoAddActiveContentToContext", checked);
            }}
          />

          <SettingItem
            type="switch"
            title="Auto-Add Selection to Context"
            description="Automatically add selected text from notes or Web Viewer (Desktop only) to chat context. Disable to use manual command instead."
            checked={settings.autoAddSelectionToContext}
            onCheckedChange={(checked) => {
              updateSetting("autoAddSelectionToContext", checked);
            }}
          />

          <SettingItem
            type="switch"
            title="Images in Markdown"
            description="Pass embedded images in markdown to the AI along with the text. Only works with multimodal models."
            checked={settings.passMarkdownImages}
            onCheckedChange={(checked) => {
              updateSetting("passMarkdownImages", checked);
            }}
          />

          <SettingItem
            type="switch"
            title="Suggested Prompts"
            description="Show suggested prompts in the chat view"
            checked={settings.showSuggestedPrompts}
            onCheckedChange={(checked) => updateSetting("showSuggestedPrompts", checked)}
          />

          <SettingItem
            type="switch"
            title="Relevant Notes"
            description="Show relevant notes in the chat view"
            checked={settings.showRelevantNotes}
            onCheckedChange={(checked) => updateSetting("showRelevantNotes", checked)}
          />
        </div>
      </section>

      {/* Saving Conversations Section */}
      <section>
        <div className="tw-mb-3 tw-text-xl tw-font-bold">Saving Conversations</div>
        <div className="tw-space-y-4">
          <SettingItem
            type="switch"
            title="Autosave Chat"
            description="Automatically saves the chat after every user message and AI response."
            checked={settings.autosaveChat}
            onCheckedChange={(checked) => updateSetting("autosaveChat", checked)}
          />

          <SettingItem
            type="switch"
            title="Generate AI Chat Title on Save"
            description="When enabled, uses an AI model to generate a concise title for saved chat notes. When disabled, uses the first 10 words of the first user message."
            checked={settings.generateAIChatTitleOnSave}
            onCheckedChange={(checked) => updateSetting("generateAIChatTitleOnSave", checked)}
          />

          <SettingItem
            type="text"
            title="Default Conversation Folder Name"
            description="The default folder name where chat conversations will be saved. Default is 'copilot/copilot-conversations'"
            value={settings.defaultSaveFolder}
            onChange={(value) => updateSetting("defaultSaveFolder", value)}
            placeholder="copilot/copilot-conversations"
          />

          <SettingItem
            type="text"
            title="Default Conversation Tag"
            description="The default tag to be used when saving a conversation. Default is 'ai-conversations'"
            value={settings.defaultConversationTag}
            onChange={(value) => updateSetting("defaultConversationTag", value)}
            placeholder="ai-conversations"
          />

          <SettingItem
            type="custom"
            title="Conversation Filename Template"
            description={
              <div className="tw-flex tw-items-start tw-gap-1.5 ">
                <span className="tw-leading-none">
                  Customize the format of saved conversation note names.
                </span>
                <HelpTooltip
                  content={
                    <div className="tw-flex tw-max-w-96 tw-flex-col tw-gap-2 tw-py-4">
                      <div className="tw-text-sm tw-font-medium tw-text-accent">
                        Note: All the following variables must be included in the template.
                      </div>
                      <div>
                        <div className="tw-text-sm tw-font-medium tw-text-muted">
                          Available variables:
                        </div>
                        <ul className="tw-pl-4 tw-text-sm tw-text-muted">
                          <li>
                            <strong>{"{$date}"}</strong>: Date in YYYYMMDD format
                          </li>
                          <li>
                            <strong>{"{$time}"}</strong>: Time in HHMMSS format
                          </li>
                          <li>
                            <strong>{"{$topic}"}</strong>: Chat conversation topic
                          </li>
                        </ul>
                        <i className="tw-mt-2 tw-text-sm tw-text-muted">
                          Example: {"{$date}_{$time}__{$topic}"} →
                          20250114_153232__polish_this_article_[[Readme]]
                        </i>
                      </div>
                    </div>
                  }
                />
              </div>
            }
          >
            <div className="tw-flex tw-w-[320px] tw-items-center tw-gap-1.5">
              <Input
                type="text"
                className={cn(
                  "tw-min-w-[80px] tw-grow tw-transition-all tw-duration-200",
                  isChecking ? "tw-w-[80px]" : "tw-w-[120px]"
                )}
                placeholder="{$date}_{$time}__{$topic}"
                value={conversationNoteName}
                onChange={(e) => setConversationNoteName(e.target.value)}
                disabled={isChecking}
              />

              <Button
                onClick={() => applyCustomNoteFormat()}
                disabled={isChecking}
                variant="secondary"
              >
                {isChecking ? (
                  <>
                    <Loader2 className="tw-mr-2 tw-size-4 tw-animate-spin" />
                    Apply
                  </>
                ) : (
                  "Apply"
                )}
              </Button>
            </div>
          </SettingItem>
        </div>
      </section>

      {/* Sorting Section */}
      <section>
        <div className="tw-mb-3 tw-text-xl tw-font-bold">Sorting</div>
        <div className="tw-space-y-4">
          <SettingItem
            type="select"
            title="Chat History Sort Strategy"
            description="Sort order for the chat history list"
            value={settings.chatHistorySortStrategy}
            onChange={(value) => {
              if (isSortStrategy(value)) {
                updateSetting("chatHistorySortStrategy", value);
              }
            }}
            options={[
              { label: "Recency", value: "recent" },
              { label: "Created", value: "created" },
              { label: "Alphabetical", value: "name" },
            ]}
          />

          <SettingItem
            type="select"
            title="Project List Sort Strategy"
            description="Sort order for the project list"
            value={settings.projectListSortStrategy}
            onChange={(value) => {
              if (isSortStrategy(value)) {
                updateSetting("projectListSortStrategy", value);
              }
            }}
            options={[
              { label: "Recency", value: "recent" },
              { label: "Created", value: "created" },
              { label: "Alphabetical", value: "name" },
            ]}
          />
        </div>
      </section>
    </div>
  );
};
