"use client";

import { Send } from "lucide-react";
import * as monaco from "monaco-editor";
import { Button } from "@/components/ui/button";
import { runCode } from "@/actions/docker/compile";
import { useEffect, useRef, useState } from "react";
import { Editor, loader } from "@monaco-editor/react";
import { MonacoLanguageClient } from "monaco-languageclient";
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import { COriginal, CplusplusOriginal, JavaOriginal } from "devicons-react";
import { connectToLanguageServer, LSP_SUPPORTED_LANGUAGES } from "@/lib/lsp";
import { codeToHtml } from "shiki";

const files: {
  [key: string]: { name: string; language: string; value: string };
} = {
  c: {
    name: "main.c",
    language: "c",
    value: `#include <stdio.h>
int main() {
    printf("Hello, World!");
    return 0;
}`,
  },
  cpp: {
    name: "main.cpp",
    language: "cpp",
    value: `#include <iostream>
int main() {
    std::cout << "Hello, World!";
    return 0;
}`,
  },
  java: {
    name: "Main.java",
    language: "java",
    value: `public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}`,
  },
};

loader.config({ monaco });

export default function PlaygroundPage() {
  const [language, setLanguage] = useState<string>("c");
  const [highlightedMessage, setHighlightedMessage] = useState<string>("");
  const file = files[language];
  const editorRef = useRef<monaco.editor.IStandaloneCodeEditor | null>(null);
  const webSocketRef = useRef<WebSocket | null>(null);
  const languageClientRef = useRef<MonacoLanguageClient | null>(null);

  useEffect(() => {
    const handleLanguageChange = async () => {
      if (editorRef.current) {
        const model = editorRef.current.getModel();
        if (model) {
          const lineCount = model.getLineCount();
          const lastLineLength = model.getLineLength(lineCount);
          editorRef.current.setPosition({
            lineNumber: lineCount,
            column: lastLineLength + 1,
          });
          editorRef.current.focus();
          if (
            languageClientRef.current &&
            language in LSP_SUPPORTED_LANGUAGES
          ) {
            await languageClientRef.current.stop();
            languageClientRef.current = null;
          }
          if (
            webSocketRef.current &&
            webSocketRef.current.readyState !== WebSocket.CLOSED &&
            webSocketRef.current.readyState !== WebSocket.CLOSING &&
            language in LSP_SUPPORTED_LANGUAGES
          ) {
            webSocketRef.current.close();
            webSocketRef.current = null;
          }
          if (language in LSP_SUPPORTED_LANGUAGES) {
            try {
              const languageClient = await connectToLanguageServer(
                language,
                webSocketRef
              );
              languageClientRef.current = languageClient;
            } catch (error) {
              console.error("Failed to connect to language server:", error);
            }
          }
        }
      }
    };

    handleLanguageChange();
  }, [language]);

  const handleSubmit = async () => {
    const code = editorRef.current?.getValue();
    if (!code) {
      console.error("No code to compile");
      return;
    }

    const result = await runCode(code, language);

    const statusMessage = result.success
      ? "Compilation successful"
      : "Compilation failed";
    const fullMessage = `${statusMessage}\n\n${result.output}`;

    const highlighted = await codeToHtml(fullMessage, {
      lang: "log",
      theme: "one-dark-pro",
    });

    setHighlightedMessage(highlighted);
  };

  return (
    <div className="h-full flex flex-col">
      <div className="flex items-center justify-between">
        <Tabs defaultValue={language as string}>
          <ScrollArea>
            <TabsList className="m-3">
              <TabsTrigger
                value="c"
                onClick={() => setLanguage("c")}
                disabled={language === "c"}
              >
                <COriginal
                  className="-ms-0.5 me-1.5"
                  size={16}
                  strokeWidth={2}
                  aria-hidden="true"
                />
                C
              </TabsTrigger>
              <TabsTrigger
                value="cpp"
                className="group"
                onClick={() => setLanguage("cpp")}
                disabled={language === "cpp"}
              >
                <CplusplusOriginal
                  className="-ms-0.5 me-1.5"
                  size={16}
                  strokeWidth={2}
                  aria-hidden="true"
                />
                C++
              </TabsTrigger>
              <TabsTrigger
                value="java"
                className="group"
                onClick={() => setLanguage("java")}
                disabled={language === "java"}
              >
                <JavaOriginal
                  className="-ms-0.5 me-1.5"
                  size={16}
                  strokeWidth={2}
                  aria-hidden="true"
                />
                Java
              </TabsTrigger>
            </TabsList>
            <ScrollBar orientation="horizontal" />
          </ScrollArea>
        </Tabs>
        <div className="m-3">
          <Button variant="outline" onClick={handleSubmit}>
            Submit
            <Send
              className="-me-1 ms-2 opacity-60"
              size={16}
              strokeWidth={2}
              aria-hidden="true"
            />
          </Button>
        </div>
      </div>
      <div className="flex flex-1 mt-0 m-3 gap-x-1">
        <div className="w-2/3">
          <Editor
            theme="vs-dark"
            path={file.name}
            defaultLanguage={file.language}
            defaultValue={file.value}
            options={{ automaticLayout: true }}
            onMount={(editor) => {
              editorRef.current = editor;
              if (editorRef.current) {
                const model = editorRef.current.getModel();
                if (model) {
                  const lineCount = model.getLineCount();
                  const lastLineLength = model.getLineLength(lineCount);
                  editorRef.current.setPosition({
                    lineNumber: lineCount,
                    column: lastLineLength + 1,
                  });
                  editorRef.current.focus();
                  connectToLanguageServer(language, webSocketRef)
                    .then((languageClient) => {
                      languageClientRef.current = languageClient;
                    })
                    .catch((error) => {
                      console.error(
                        "Failed to connect to language server:",
                        error
                      );
                    });
                }
              }
            }}
          />
        </div>
        <div className="h-full w-1/3">
          <div dangerouslySetInnerHTML={{ __html: highlightedMessage }} />
        </div>
      </div>
    </div>
  );
}
