import { useEffect, useState } from "react";
import type { Suggestion } from "@codeflash/types";
import styles from "../styles/initForm.module.css";
import Dropdown, { type DropdownOption } from "./dropdown";
import dropdownStyles from "./dropdown/Dropdown.module.css";
import { vscode } from "../utils/vscode";
import { useStore } from "../store/root";
import HelpButton from "./helpButton";

type Props = {
  suggestions: Record<string, Suggestion>;
  errorDetails: string | undefined;
  pyprojectPath: string | undefined;
};

type FormData = {
  module_root: string;
  tests_root: string;
  formatter_cmds: string;
};

const CUSTOM_OPTION = "__custom__";

const CUSTOM_OPTIONS: Record<
  keyof FormData,
  { label: string; value: string }[]
> = {
  module_root: [
    { label: "Custom path...", value: CUSTOM_OPTION },
    { label: "Current directory", value: "." },
  ],
  tests_root: [{ label: "Custom path...", value: CUSTOM_OPTION }],
  formatter_cmds: [{ label: "Custom formatter cmd", value: CUSTOM_OPTION }],
};

const requiredFields: (keyof FormData)[] = ["module_root", "tests_root"];

const InitForm = ({ suggestions, errorDetails, pyprojectPath }: Props) => {
  const [formData, setFormData] = useState<FormData>({
    module_root: suggestions.module_root?.default || "",
    tests_root: suggestions.tests_root?.default || "",
    formatter_cmds: suggestions.formatter_cmds?.default || "",
  });
  const [isLoading, setIsLoading] = useState(false);
  const [fieldErrors, setFieldErrors] = useState<
    Record<keyof FormData, string>
  >({
    module_root: "",
    tests_root: "",
    formatter_cmds: "",
  });

  const [customPaths, setCustomPaths] = useState({
    module_root: false,
    tests_root: false,
  });
  const renderedOnPurpose = !errorDetails;

  // Expose setFieldErrors function to window for external access
  useEffect(() => {
    (window as any).setInitFormFieldErrors = (
      errors: Record<string, string>,
    ) => {
      setFieldErrors((prev) => ({
        ...prev,
        ...errors,
      }));
    };
    return () => {
      delete (window as any).setInitFormFieldErrors;
    };
  }, []);

  // Helper to get directory name from path
  const getConfigDirectory = () => {
    if (!pyprojectPath) {
      return "workspace root";
    }
    const parts = pyprojectPath.split("/");
    return parts.length > 1 ? parts.slice(0, -1).join("/") : ".";
  };

  const setActiveTab = renderedOnPurpose
    ? useStore((state) => state.setActiveTab)
    : undefined;

  const handleInputChange = (field: keyof FormData, value: string) => {
    setFormData((prev) => ({
      ...prev,
      [field]: value,
    }));

    // Clear error for this field when user starts typing
    // if (fieldErrors[field]) {
    //   setFieldErrors((prev) => ({
    //     ...prev,
    //     [field]: "",
    //   }));
    // }
  };

  useEffect(() => {
    if (Object.keys(suggestions).length === 0) {
      return;
    }
    const defaultModuleRoot = suggestions.module_root?.default || "";
    const defaultTestsRoot = suggestions.tests_root?.default || "";
    const defaultFormatterCmds = suggestions.formatter_cmds?.default || "";

    setFormData({
      module_root: defaultModuleRoot,
      tests_root: defaultTestsRoot,
      formatter_cmds: defaultFormatterCmds,
    });

    handleConfiguredCustomValues();
  }, [suggestions]);

  const handleConfiguredCustomValues = () => {
    const keys: (keyof FormData)[] = [
      "module_root",
      "tests_root",
      "formatter_cmds",
    ];

    for (const key of keys) {
      const configuredValue = suggestions[key]?.default;
      if (!configuredValue) {
        continue;
      }

      const isCustomValue =
        !suggestions[key]?.choices?.includes(configuredValue);
      if (!isCustomValue) {
        continue;
      }
      if (key === "module_root" && configuredValue === ".") {
        // Default value representing current directory, skip marking as custom
        continue;
      }
      setCustomPaths((prev) => ({
        ...prev,
        [key]: true,
      }));
    }
  };

  useEffect(() => {
    const messageListener = async (event: MessageEvent) => {
      const message = event.data;
      if (message.command === "setInitFormLoadingState") {
        const loadingState: boolean = message.isLoading;
        if (!loadingState) {
          // loading is done, leave some time until the pooling re-checks the new config
          await new Promise((resolve) => setTimeout(resolve, 2000));
          setIsLoading(loadingState);
        } else {
          setIsLoading(loadingState);
        }
      }
    };

    window.addEventListener("message", messageListener);
    return () => {
      window.removeEventListener("message", messageListener);
    };
  }, []);

  const handleDropdownChange = (field: keyof FormData, value: string) => {
    if (value === CUSTOM_OPTION) {
      // Switch to custom input mode
      setCustomPaths((prev) => ({
        ...prev,
        [field]: true,
      }));
      setFormData((prev) => ({
        ...prev,
        [field]: "",
      }));
    } else {
      // Regular selection
      setCustomPaths((prev) => ({
        ...prev,
        [field]: false,
      }));
      handleInputChange(field, value);
    }
  };

  const validateRelativePath = (path: string): string => {
    if (!path || !path.trim()) {
      return "";
    }

    const trimmed = path.trim();
    const normalized = trimmed.replace(/\\/g, "/");

    // Check for path traversal
    if (normalized.includes("..")) {
      return "Path cannot contain '..' (parent directory traversal)";
    }

    // Check for absolute paths
    if (
      trimmed.startsWith("/") ||
      (trimmed.length >= 2 && trimmed[1] === ":") // Windows drive letter
    ) {
      return "Path must be relative, not absolute";
    }

    // Check for shell commands or dangerous patterns
    const dangerousPatterns = [
      "cd ",
      "ls ",
      "rm ",
      "mkdir ",
      "rmdir ",
      "del ",
      "dir ",
      "type ",
      "cat ",
      "echo ",
      "&&",
      "||",
      ";",
      "|",
      ">",
      "<",
      "$",
      "`",
    ];
    const pathLower = trimmed.toLowerCase();
    for (const pattern of dangerousPatterns) {
      if (pathLower.includes(pattern)) {
        return `Path contains invalid characters or commands: ${pattern.trim()}`;
      }
    }

    // Check for invalid characters (OS-agnostic check)
    const invalidChars = /[<>:"|?*\x00]/;
    if (invalidChars.test(trimmed)) {
      return "Path contains invalid characters";
    }

    return "";
  };

  const validateFormData = (): boolean => {
    const errors: Record<keyof FormData, string> = {
      module_root: "",
      tests_root: "",
      formatter_cmds: "",
    };

    let hasErrors = false;

    // Check required fields
    requiredFields.forEach((field) => {
      const value = formData[field].trim();
      if (!value) {
        errors[field] = `${field.replace(/_/g, " ")} is required`;
        hasErrors = true;
      }
    });

    // Validate module_root path
    if (formData.module_root.trim()) {
      const moduleError = validateRelativePath(formData.module_root);
      if (moduleError) {
        errors.module_root = moduleError;
        hasErrors = true;
      }
    }

    // Validate tests_root path
    if (formData.tests_root.trim()) {
      const testsError = validateRelativePath(formData.tests_root);
      if (testsError) {
        errors.tests_root = testsError;
        hasErrors = true;
      }
    }

    // Special validation for formatter_cmds
    const isCustomFormatter = !suggestions.formatter_cmds?.choices.includes(
      formData.formatter_cmds,
    );
    if (isCustomFormatter) {
      const formatterCmd = formData.formatter_cmds.trim();
      if (!formatterCmd.includes("$file")) {
        errors.formatter_cmds =
          "Custom formatter commands must include $file placeholder (e.g., 'black $file')";
        hasErrors = true;
      }
    }

    setFieldErrors(errors);
    return !hasErrors;
  };

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    const isValid = validateFormData();
    if (!isValid) {
      return;
    }
    vscode.postMessage({
      type: "submitInitForm",
      payload: { formData, pyprojectPath: pyprojectPath || "" },
    });
  };

  const renderField = (
    field: keyof FormData,
    label: string,
    description: string,
    allowCustomPath = false,
    customPathPlaceholder = "Enter custom path relative to pyproject.toml",
  ) => {
    const suggestion = suggestions[field];
    const isCustomPath =
      allowCustomPath && customPaths[field as "module_root" | "tests_root"];
    const hasError = !!fieldErrors[field];

    const customOptions = CUSTOM_OPTIONS[field] || [];
    // Convert suggestion choices to dropdown options and add custom option
    const dropdownOptions: DropdownOption[] = [
      ...customOptions,
      ...(suggestion?.choices.map((choice) => ({
        value: choice,
        label: choice,
      })) || []),
    ];

    return (
      <div className={styles.field}>
        <label className={styles.label}>
          <span>
            {label} {requiredFields.includes(field) && "*"}
          </span>
          <span className={styles.description}>{description}</span>
        </label>

        {isCustomPath ? (
          <div className={styles.customInputContainer}>
            <input
              type="text"
              className={`${styles.input} ${hasError ? styles.inputError : ""}`}
              value={formData[field]}
              onChange={(e) => handleInputChange(field, e.target.value)}
              placeholder={customPathPlaceholder}
              autoFocus
            />
            <button
              type="button"
              role="button"
              className={styles.backButton}
              onClick={(e) => {
                e.preventDefault();
                setCustomPaths((prev) => ({ ...prev, [field]: false }));
                setFormData((prev) => ({
                  ...prev,
                  [field]: suggestion?.default || "",
                }));
                // Clear error when switching back
                if (fieldErrors[field]) {
                  setFieldErrors((prev) => ({
                    ...prev,
                    [field]: "",
                  }));
                }
              }}
              title="Back to options"
            >
              <span className="codicon codicon-close"></span>
            </button>
          </div>
        ) : (
          <Dropdown
            options={dropdownOptions}
            value={formData[field]}
            onChange={(value) => handleDropdownChange(field, value)}
            placeholder={`Select ${label.toLowerCase()}`}
            className={hasError ? dropdownStyles.dropdownError : ""}
          />
        )}

        {hasError && (
          <div className={styles.errorMessage}>
            <span
              className={styles.errorIcon + " codicon codicon-warning"}
            ></span>
            {fieldErrors[field]}
          </div>
        )}
      </div>
    );
  };

  return (
    <div className={styles.container}>
      <div className={styles.helpBtnWrapper}>
        <HelpButton />
      </div>
      <form
        onKeyDown={(e) => {
          if (e.key === "Enter") {
            e.preventDefault();
          }
        }}
        onSubmit={handleSubmit}
        className={styles.form}
      >
        <h2 className={styles.title}>Project Configuration</h2>

        {/* Context info section */}
        <div className={styles.contextInfo}>
          <div className={styles.contextItem}>
            <span className="codicon codicon-file"></span>
            <span>
              Config file:{" "}
              <code>{pyprojectPath || "pyproject.toml (will be created)"}</code>
            </span>
          </div>
          <div className={styles.helpText}>
            💡 All paths below are relative to{" "}
            <code>{getConfigDirectory()}</code>
          </div>
        </div>

        {errorDetails && (
          <p
            className={styles.bannerError}
            dangerouslySetInnerHTML={{
              __html:
                `<span
class="${styles.codicon} codicon-warning"
style="color: var(--vscode-editorWarning-foreground);"></span>` + errorDetails,
            }}
          ></p>
        )}

        {renderField(
          "module_root",
          "Module Root",
          "Path relative to pyproject.toml where your source code is located.",
          true,
          "e.g., src, src/app, lib, app, or . for current directory",
        )}

        {renderField(
          "tests_root",
          "Tests Root",
          "Path relative to pyproject.toml where your test files are located (common: tests, test, __tests__)",
          true,
          "e.g., tests, test",
        )}

        {renderField(
          "formatter_cmds",
          "Formatter",
          "formatter used in your project, for custom commands use `$file` as a placeholder for the file path",
          true,
          "e.g. black $file",
        )}

        <div className={styles.formActions}>
          {renderedOnPurpose && (
            <button
              onClick={() => {
                setActiveTab && setActiveTab("optimization");
              }}
              type="button"
              role="button"
              className={styles.cancelButton}
            >
              Back
            </button>
          )}
          <button
            type="submit"
            className={styles.submitButton}
            disabled={isLoading}
          >
            {isLoading ? (
              <>
                <span className="codicon codicon-loading spin"></span>
                {" Saving..."}
              </>
            ) : (
              <>
                <span className="codicon codicon-save"></span>
                {" Save & Apply Configuration"}
              </>
            )}
          </button>
        </div>
        {!isLoading && (
          <div className={styles.actionHelp}>
            {pyprojectPath ? "This will update" : "This will create"} your
            pyproject.toml and reload the extension
          </div>
        )}
      </form>
    </div>
  );
};

export default InitForm;
