import * as React from "react";
import { api } from "./api/client";
import { Chat } from "./components/Chat";
import "./App.css";

function isFuzzyMatch(candidate: string, query: string) {
  if (!query) return true;
  const lowerCandidate = candidate.toLowerCase();
  const lowerQuery = query.toLowerCase();
  let idx = 0;
  for (const char of lowerQuery) {
    idx = lowerCandidate.indexOf(char, idx);
    if (idx === -1) return false;
    idx += 1;
  }
  return true;
}

function getCurrentPartial(input: string) {
  const trimmed = input.trim();
  if (!trimmed) return "";
  if (trimmed.endsWith("/")) return "";
  const idx = trimmed.lastIndexOf("/");
  return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
}

function renderHighlightedMatch(text: string, query: string) {
  if (!query) return text;
  let qIndex = 0;
  const lowerQuery = query.toLowerCase();
  const counts = new Map<string, number>();
  return text.split("").map((char) => {
    const isMatch =
      qIndex < lowerQuery.length && char.toLowerCase() === lowerQuery[qIndex];
    if (isMatch) {
      qIndex += 1;
    }
    const count = counts.get(char) ?? 0;
    counts.set(char, count + 1);
    return (
      <span
        key={`${char}-${count}`}
        style={isMatch ? { fontWeight: 600, color: "#222" } : undefined}
      >
        {char}
      </span>
    );
  });
}

function App() {
  const [projectPath, setProjectPath] = React.useState<string | null>(null);
  const [errorMsg, setErrorMsg] = React.useState<string | null>(null);
  const [pathInput, setPathInput] = React.useState("");
  const [isOpening, setIsOpening] = React.useState(false);
  const [knownProjects, setKnownProjects] = React.useState<string[]>([]);
  const [homeDir, setHomeDir] = React.useState<string | null>(null);

  const [suggestionTail, setSuggestionTail] = React.useState("");
  const [completionError, setCompletionError] = React.useState<string | null>(
    null,
  );
  const [matchList, setMatchList] = React.useState<
    { name: string; path: string }[]
  >([]);
  const [selectedMatch, setSelectedMatch] = React.useState(0);

  React.useEffect(() => {
    api
      .getKnownProjects()
      .then((projects) => setKnownProjects(projects))
      .catch((error) => console.error(error));
  }, []);

  React.useEffect(() => {
    let active = true;
    api
      .getHomeDirectory()
      .then((home) => {
        if (!active) return;
        setHomeDir(home);
        setPathInput((current) => {
          if (current.trim()) {
            return current;
          }
          const initial = home.endsWith("/") ? home : `${home}/`;
          return initial;
        });
      })
      .catch((error) => {
        console.error(error);
      });

    return () => {
      active = false;
    };
  }, []);

  React.useEffect(() => {
    let active = true;

    async function computeSuggestion() {
      setCompletionError(null);
      setSuggestionTail("");
      setMatchList([]);
      setSelectedMatch(0);

      const trimmed = pathInput.trim();
      if (!trimmed) {
        return;
      }

      const endsWithSlash = trimmed.endsWith("/");
      let dir = trimmed;
      let partial = "";

      if (!endsWithSlash) {
        const idx = trimmed.lastIndexOf("/");
        if (idx >= 0) {
          dir = trimmed.slice(0, idx + 1);
          partial = trimmed.slice(idx + 1);
        } else {
          dir = "";
          partial = trimmed;
        }
      }

      if (!dir) {
        if (homeDir) {
          dir = homeDir.endsWith("/") ? homeDir : `${homeDir}/`;
        } else {
          return;
        }
      }

      const dirForListing = dir === "/" ? "/" : dir.replace(/\/+$/, "");
      const entries = await api.listDirectoryAbsolute(dirForListing);
      if (!active) return;

      const matches = entries
        .filter((entry) => entry.kind === "dir")
        .filter((entry) => isFuzzyMatch(entry.name, partial))
        .sort((a, b) => a.name.localeCompare(b.name))
        .slice(0, 8);

      if (matches.length === 0) {
        return;
      }

      const basePrefix = dir.endsWith("/") ? dir : `${dir}/`;
      const list = matches.map((entry) => ({
        name: entry.name,
        path: `${basePrefix}${entry.name}/`,
      }));
      setMatchList(list);
    }

    const debounceId = window.setTimeout(() => {
      computeSuggestion().catch((error) => {
        console.error(error);
        if (!active) return;
        setCompletionError(
          error instanceof Error
            ? error.message
            : "Failed to compute suggestion.",
        );
      });
    }, 60);

    return () => {
      active = false;
      window.clearTimeout(debounceId);
    };
  }, [pathInput, homeDir]);

  React.useEffect(() => {
    if (matchList.length === 0) {
      setSuggestionTail("");
      return;
    }
    const index = Math.min(selectedMatch, matchList.length - 1);
    const next = matchList[index];
    const trimmed = pathInput.trim();
    if (next.path.startsWith(trimmed)) {
      setSuggestionTail(next.path.slice(trimmed.length));
    } else {
      setSuggestionTail("");
    }
  }, [matchList, selectedMatch, pathInput]);

  async function openProject(path: string) {
    if (!path.trim()) {
      setErrorMsg("Please enter a project path.");
      return;
    }

    try {
      setErrorMsg(null);
      setIsOpening(true);
      const confirmedPath = await api.openProject(path.trim());
      setProjectPath(confirmedPath);
    } catch (e) {
      console.error(e);
      const message =
        e instanceof Error
          ? e.message
          : typeof e === "string"
            ? e
            : "An error occurred opening the project.";
      setErrorMsg(message);
    } finally {
      setIsOpening(false);
    }
  }

  function handleOpen() {
    void openProject(pathInput);
  }

  async function closeProject() {
    try {
      await api.closeProject();
      setProjectPath(null);
    } catch (e) {
      console.error(e);
    }
  }

  const currentPartial = getCurrentPartial(pathInput);

  return (
    <main
      className="container"
      style={{ height: "100vh", padding: 0, maxWidth: "100%" }}
    >
      {!projectPath ? (
        <div
          className="selection-screen"
          style={{ padding: "2rem", maxWidth: "800px", margin: "0 auto" }}
        >
          <h1>AI Code Assistant</h1>
          <p>Paste or complete a project path to start.</p>
          {knownProjects.length > 0 && (
            <div style={{ marginTop: "12px" }}>
              <div style={{ fontSize: "0.9em", color: "#666" }}>
                Recent projects
              </div>
              <ul style={{ listStyle: "none", padding: 0, margin: "8px 0 0" }}>
                {knownProjects.map((project) => {
                  const displayName =
                    project.split("/").filter(Boolean).pop() ?? project;
                  return (
                    <li key={project} style={{ marginBottom: "6px" }}>
                      <div
                        style={{
                          display: "flex",
                          gap: "6px",
                          alignItems: "center",
                        }}
                      >
                        <button
                          type="button"
                          onClick={() => void openProject(project)}
                          style={{
                            flex: 1,
                            textAlign: "left",
                            padding: "8px 10px",
                            borderRadius: "6px",
                            border: "1px solid #ddd",
                            background: "#f7f7f7",
                            cursor: "pointer",
                            fontFamily: "monospace",
                            fontSize: "0.9em",
                          }}
                          title={project}
                        >
                          {displayName}
                        </button>
                        <button
                          type="button"
                          aria-label={`Forget ${displayName}`}
                          onClick={() => {
                            void (async () => {
                              try {
                                await api.forgetKnownProject(project);
                                setKnownProjects((prev) =>
                                  prev.filter((p) => p !== project),
                                );
                              } catch (error) {
                                console.error(error);
                              }
                            })();
                          }}
                          style={{
                            width: "32px",
                            height: "32px",
                            borderRadius: "6px",
                            border: "1px solid #ddd",
                            background: "#fff",
                            cursor: "pointer",
                            fontSize: "1.1em",
                            lineHeight: 1,
                          }}
                        >
                          ×
                        </button>
                      </div>
                    </li>
                  );
                })}
              </ul>
            </div>
          )}

          <div
            style={{
              position: "relative",
              marginTop: "12px",
              marginBottom: "170px",
            }}
          >
            <div
              style={{
                position: "absolute",
                inset: 0,
                padding: "10px",
                color: "#aaa",
                fontFamily: "monospace",
                whiteSpace: "pre",
                overflow: "hidden",
                textOverflow: "ellipsis",
                pointerEvents: "none",
              }}
            >
              {pathInput}
              {suggestionTail}
            </div>
            <input
              type="text"
              value={pathInput}
              placeholder="/path/to/project"
              onChange={(event) => setPathInput(event.target.value)}
              onKeyDown={(event) => {
                if (event.key === "ArrowDown") {
                  if (matchList.length > 0) {
                    event.preventDefault();
                    setSelectedMatch((prev) => (prev + 1) % matchList.length);
                  }
                } else if (event.key === "ArrowUp") {
                  if (matchList.length > 0) {
                    event.preventDefault();
                    setSelectedMatch(
                      (prev) =>
                        (prev - 1 + matchList.length) % matchList.length,
                    );
                  }
                } else if (event.key === "Tab") {
                  if (matchList.length > 0) {
                    event.preventDefault();
                    const next = matchList[selectedMatch]?.path;
                    if (next) {
                      setPathInput(next);
                    }
                  }
                } else if (event.key === "Escape") {
                  event.preventDefault();
                  setMatchList([]);
                  setSelectedMatch(0);
                  setSuggestionTail("");
                  setCompletionError(null);
                } else if (event.key === "Enter") {
                  handleOpen();
                }
              }}
              style={{
                width: "100%",
                padding: "10px",
                fontFamily: "monospace",
                background: "transparent",
                position: "relative",
                zIndex: 1,
              }}
            />
            {matchList.length > 0 && (
              <div
                style={{
                  position: "absolute",
                  top: "100%",
                  left: 0,
                  right: 0,
                  marginTop: "6px",
                  border: "1px solid #ddd",
                  borderRadius: "6px",
                  overflow: "hidden",
                  background: "#fff",
                  fontFamily: "monospace",
                  height: "160px",
                  overflowY: "auto",
                  boxSizing: "border-box",
                  zIndex: 2,
                }}
              >
                <div
                  style={{
                    display: "flex",
                    justifyContent: "flex-end",
                    alignItems: "center",
                    padding: "4px 6px",
                    borderBottom: "1px solid #eee",
                    background: "#fafafa",
                  }}
                >
                  <button
                    type="button"
                    aria-label="Close suggestions"
                    onClick={() => {
                      setMatchList([]);
                      setSelectedMatch(0);
                      setSuggestionTail("");
                      setCompletionError(null);
                    }}
                    style={{
                      width: "24px",
                      height: "24px",
                      borderRadius: "4px",
                      border: "1px solid #ddd",
                      background: "#fff",
                      cursor: "pointer",
                      lineHeight: 1,
                    }}
                  >
                    ×
                  </button>
                </div>
                {matchList.map((match, index) => {
                  const isSelected = index === selectedMatch;
                  return (
                    <button
                      key={match.path}
                      type="button"
                      onMouseEnter={() => setSelectedMatch(index)}
                      onMouseDown={(event) => {
                        event.preventDefault();
                        setSelectedMatch(index);
                        setPathInput(match.path);
                      }}
                      style={{
                        width: "100%",
                        textAlign: "left",
                        padding: "6px 8px",
                        border: "none",
                        background: isSelected ? "#f0f0f0" : "transparent",
                        cursor: "pointer",
                        fontFamily: "inherit",
                      }}
                    >
                      {renderHighlightedMatch(match.name, currentPartial)}/
                    </button>
                  );
                })}
              </div>
            )}
          </div>

          <div
            style={{
              display: "flex",
              gap: "8px",
              marginTop: "8px",
              alignItems: "center",
            }}
          >
            <button type="button" onClick={handleOpen} disabled={isOpening}>
              {isOpening ? "Opening..." : "Open Project"}
            </button>
            <div style={{ fontSize: "0.85em", color: "#666" }}>
              Press Tab to complete the next path segment
            </div>
          </div>

          {completionError && (
            <div style={{ color: "red", marginTop: "8px" }}>
              {completionError}
            </div>
          )}
        </div>
      ) : (
        <div className="workspace" style={{ height: "100%" }}>
          <Chat projectPath={projectPath} onCloseProject={closeProject} />
        </div>
      )}

      {errorMsg && (
        <div className="error-message" style={{ marginTop: "20px" }}>
          <p style={{ color: "red" }}>Error: {errorMsg}</p>
        </div>
      )}
    </main>
  );
}

export default App;
