import React from "react";
import { useSelector } from "react-redux";
import { IoAlertCircle } from "react-icons/io5";
import { useTranslation } from "react-i18next";
import { Editor, Monaco } from "@monaco-editor/react";
import { editor } from "monaco-editor";
import { Button, Select, SelectItem } from "@heroui/react";
import { useMutation } from "@tanstack/react-query";
import { RootState } from "#/store";
import {
  ActionSecurityRisk,
  SecurityAnalyzerLog,
} from "#/state/security-analyzer-slice";
import { useScrollToBottom } from "#/hooks/use-scroll-to-bottom";
import { I18nKey } from "#/i18n/declaration";
import toast from "#/utils/toast";
import InvariantLogoIcon from "./assets/logo";
import { getFormattedDateTime } from "#/utils/gget-formatted-datetime";
import { downloadJSON } from "#/utils/download-json";
import InvariantService from "#/api/invariant-service";
import { useGetPolicy } from "#/hooks/query/use-get-policy";
import { useGetRiskSeverity } from "#/hooks/query/use-get-risk-severity";
import { useGetTraces } from "#/hooks/query/use-get-traces";

type SectionType = "logs" | "policy" | "settings";

function SecurityInvariant() {
  const { t } = useTranslation();
  const { logs } = useSelector((state: RootState) => state.securityAnalyzer);

  const [activeSection, setActiveSection] = React.useState("logs");
  const [policy, setPolicy] = React.useState("");
  const [selectedRisk, setSelectedRisk] = React.useState(
    ActionSecurityRisk.MEDIUM,
  );

  const logsRef = React.useRef<HTMLDivElement>(null);

  useGetPolicy({ onSuccess: setPolicy });

  useGetRiskSeverity({
    onSuccess: (riskSeverity) => {
      setSelectedRisk(
        riskSeverity === 0
          ? ActionSecurityRisk.LOW
          : riskSeverity || ActionSecurityRisk.MEDIUM,
      );
    },
  });

  const { refetch: exportTraces } = useGetTraces({
    onSuccess: (traces) => {
      toast.info(t(I18nKey.INVARIANT$TRACE_EXPORTED_MESSAGE));

      const filename = `openhands-trace-${getFormattedDateTime()}.json`;
      downloadJSON(traces, filename);
    },
  });

  const { mutate: updatePolicy } = useMutation({
    mutationFn: (variables: { policy: string }) =>
      InvariantService.updatePolicy(variables.policy),
    onSuccess: () => {
      toast.info(t(I18nKey.INVARIANT$POLICY_UPDATED_MESSAGE));
    },
  });

  const { mutate: updateRiskSeverity } = useMutation({
    mutationFn: (variables: { riskSeverity: number }) =>
      InvariantService.updateRiskSeverity(variables.riskSeverity),
    onSuccess: () => {
      toast.info(t(I18nKey.INVARIANT$SETTINGS_UPDATED_MESSAGE));
    },
  });

  useScrollToBottom(logsRef);

  const getRiskColor = React.useCallback((risk: ActionSecurityRisk) => {
    switch (risk) {
      case ActionSecurityRisk.LOW:
        return "text-green-500";
      case ActionSecurityRisk.MEDIUM:
        return "text-yellow-500";
      case ActionSecurityRisk.HIGH:
        return "text-red-500";
      case ActionSecurityRisk.UNKNOWN:
      default:
        return "text-gray-500";
    }
  }, []);

  const getRiskText = React.useCallback(
    (risk: ActionSecurityRisk) => {
      switch (risk) {
        case ActionSecurityRisk.LOW:
          return t(I18nKey.SECURITY_ANALYZER$LOW_RISK);
        case ActionSecurityRisk.MEDIUM:
          return t(I18nKey.SECURITY_ANALYZER$MEDIUM_RISK);
        case ActionSecurityRisk.HIGH:
          return t(I18nKey.SECURITY_ANALYZER$HIGH_RISK);
        case ActionSecurityRisk.UNKNOWN:
        default:
          return t(I18nKey.SECURITY_ANALYZER$UNKNOWN_RISK);
      }
    },
    [t],
  );

  const handleEditorDidMount = React.useCallback(
    (_: editor.IStandaloneCodeEditor, monaco: Monaco): void => {
      monaco.editor.defineTheme("my-theme", {
        base: "vs-dark",
        inherit: true,
        rules: [],
        colors: {
          "editor.background": "#171717",
        },
      });

      monaco.editor.setTheme("my-theme");
    },
    [],
  );

  const sections: Record<SectionType, React.ReactNode> = {
    logs: (
      <>
        <div className="flex justify-between items-center border-b border-neutral-600 mb-4 p-4">
          <h2 className="text-2xl">{t(I18nKey.INVARIANT$LOG_LABEL)}</h2>
          <Button onPress={() => exportTraces()} className="bg-tertiary">
            {t(I18nKey.INVARIANT$EXPORT_TRACE_LABEL)}
          </Button>
        </div>
        <div
          className="flex-1 p-4 max-h-screen overflow-y-auto fast-smooth-scroll"
          ref={logsRef}
        >
          {logs.map((log: SecurityAnalyzerLog, index: number) => (
            <div
              key={index}
              className={`mb-2 p-2 rounded-lg ${log.confirmed_changed && log.confirmation_state === "confirmed" ? "border-green-800" : "border-red-800"}`}
              style={{
                backgroundColor: "rgba(128, 128, 128, 0.2)",
                borderWidth: log.confirmed_changed ? "2px" : "0",
              }}
            >
              <p className="text-sm relative break-words">
                {log.content}
                {(log.confirmation_state === "awaiting_confirmation" ||
                  log.confirmed_changed) && (
                  <IoAlertCircle className="absolute top-0 right-0" />
                )}
              </p>
              <p className={`text-xs ${getRiskColor(log.security_risk)}`}>
                {getRiskText(log.security_risk)}
              </p>
            </div>
          ))}
        </div>
      </>
    ),
    policy: (
      <>
        <div className="flex justify-between items-center border-b border-neutral-600 mb-4 p-4">
          <h2 className="text-2xl">{t(I18nKey.INVARIANT$POLICY_LABEL)}</h2>
          <Button
            className="bg-tertiary"
            onPress={() => updatePolicy({ policy })}
          >
            {t(I18nKey.INVARIANT$UPDATE_POLICY_LABEL)}
          </Button>
        </div>
        <div className="flex grow items-center justify-center">
          <Editor
            path="policy.py"
            height="100%"
            onMount={handleEditorDidMount}
            value={policy}
            onChange={(value) => setPolicy(value || "")}
          />
        </div>
      </>
    ),
    settings: (
      <>
        <div className="flex justify-between items-center border-b border-neutral-600 mb-4 p-4">
          <h2 className="text-2xl">{t(I18nKey.INVARIANT$SETTINGS_LABEL)}</h2>
          <Button
            className="bg-tertiary"
            onPress={() => updateRiskSeverity({ riskSeverity: selectedRisk })}
          >
            {t(I18nKey.INVARIANT$UPDATE_SETTINGS_LABEL)}
          </Button>
        </div>
        <div className="flex grow p-4">
          <div className="flex flex-col w-full">
            <p className="mb-2">
              {t(I18nKey.INVARIANT$ASK_CONFIRMATION_RISK_SEVERITY_LABEL)}
            </p>
            <Select
              placeholder="Select risk severity"
              value={selectedRisk}
              onChange={(e) =>
                setSelectedRisk(Number(e.target.value) as ActionSecurityRisk)
              }
              className={getRiskColor(selectedRisk)}
              selectedKeys={new Set([selectedRisk.toString()])}
              aria-label="Select risk severity"
            >
              <SelectItem
                key={ActionSecurityRisk.UNKNOWN}
                aria-label="Unknown Risk"
                className={getRiskColor(ActionSecurityRisk.UNKNOWN)}
              >
                {getRiskText(ActionSecurityRisk.UNKNOWN)}
              </SelectItem>
              <SelectItem
                key={ActionSecurityRisk.LOW}
                aria-label="Low Risk"
                className={getRiskColor(ActionSecurityRisk.LOW)}
              >
                {getRiskText(ActionSecurityRisk.LOW)}
              </SelectItem>
              <SelectItem
                key={ActionSecurityRisk.MEDIUM}
                aria-label="Medium Risk"
                className={getRiskColor(ActionSecurityRisk.MEDIUM)}
              >
                {getRiskText(ActionSecurityRisk.MEDIUM)}
              </SelectItem>
              <SelectItem
                key={ActionSecurityRisk.HIGH}
                aria-label="High Risk"
                className={getRiskColor(ActionSecurityRisk.HIGH)}
              >
                {getRiskText(ActionSecurityRisk.HIGH)}
              </SelectItem>
              <SelectItem
                key={ActionSecurityRisk.HIGH + 1}
                aria-label="Don't ask for confirmation"
              >
                {t(I18nKey.INVARIANT$DONT_ASK_FOR_CONFIRMATION_LABEL)}
              </SelectItem>
            </Select>
          </div>
        </div>
      </>
    ),
  };

  return (
    <div className="flex flex-1 w-full h-full">
      <div className="w-60 bg-base-secondary border-r border-r-neutral-600 p-4 flex-shrink-0">
        <div className="text-center mb-2">
          <InvariantLogoIcon className="mx-auto mb-1" />
          <b>{t(I18nKey.INVARIANT$INVARIANT_ANALYZER_LABEL)}</b>
        </div>
        <p className="text-[0.6rem]">
          {t(I18nKey.INVARIANT$INVARIANT_ANALYZER_MESSAGE)}{" "}
          <a
            className="underline"
            href="https://github.com/invariantlabs-ai/invariant"
            target="_blank"
            rel="noreferrer"
          >
            {t(I18nKey.INVARIANT$CLICK_TO_LEARN_MORE_LABEL)}
          </a>
        </p>
        <hr className="border-t border-neutral-600 my-2" />
        <ul className="space-y-2">
          <div
            className={`cursor-pointer p-2 rounded ${activeSection === "logs" && "bg-neutral-600"}`}
            onClick={() => setActiveSection("logs")}
          >
            {t(I18nKey.INVARIANT$LOG_LABEL)}
          </div>
          <div
            className={`cursor-pointer p-2 rounded ${activeSection === "policy" && "bg-neutral-600"}`}
            onClick={() => setActiveSection("policy")}
          >
            {t(I18nKey.INVARIANT$POLICY_LABEL)}
          </div>
          <div
            className={`cursor-pointer p-2 rounded ${activeSection === "settings" && "bg-neutral-600"}`}
            onClick={() => setActiveSection("settings")}
          >
            {t(I18nKey.INVARIANT$SETTINGS_LABEL)}
          </div>
        </ul>
      </div>
      <div className="flex flex-col min-h-0 w-full overflow-y-auto bg-base">
        {sections[activeSection as SectionType]}
      </div>
    </div>
  );
}

export default SecurityInvariant;
