import { useEffect, useState } from "react";
import { Link, Outlet, useOutletContext } from "@remix-run/react/dist";
import { useSocket } from "../context";
import { L33tTask } from "l33t-lib";
import { L33tMemDB } from "l33t-lib";
import TimedStatus from "../components/TimedStatus";

type ContextType = {
  toggleSelection: (id: string) => void;
  selectedIds: string[];
  memoryDB: L33tMemDB;
};

interface HTMLRendererProps {
  html: string;
  className?: string;
}

const HTMLRenderer: React.FC<HTMLRendererProps> = ({ html, className = "" }) => (
  <div
    className={`prose prose-invert max-w-none ${className}`}
    dangerouslySetInnerHTML={{ __html: html }}
  />
);

interface ErrorDisplayProps {
  error: string;
}

const ErrorDisplay: React.FC<ErrorDisplayProps> = ({ error }) => (
  <div className="bg-red-950/50 border border-red-500/50 rounded-lg p-4 mt-2">
    <div className="flex items-center gap-2 text-red-400">
      <span className="font-semibold">Error</span>
    </div>
    <p className="mt-2 text-red-200 text-sm">{error}</p>
  </div>
);

export default function Tasks() {
  const { memoryDB, toggleSelection, selectedIds } = useOutletContext<ContextType>();
  const [tasks, setTasks] = useState<Record<string, L33tTask>>({});
  const socket = useSocket();

  useEffect(() => {
    if (!socket) return;

    const handleL33tUpdate = (obj: { key: string; task: L33tTask }) => {
      setTasks(prev => ({
        ...prev,
        [obj.key]: obj.task
      }));
    };
  
    const handleTaskUpdate = (taskId: string, task: L33tTask | null) => {
      setTasks(prev => {
        if (task === null) {
          const newTasks = { ...prev };
          delete newTasks[taskId];
          return newTasks;
        }
        return { 
          ...prev,
          [taskId]: task
        };
      });
    };
  
    socket.on("l33t_task_exec", handleL33tUpdate);
    socket.on("l33t_task_update", handleTaskUpdate);
    socket.on("l33t_delete_task_result", result => {
      if (!result.success) console.error("Delete failed:", result.error);
    });

    return () => {
      socket.off("l33t_task_exec", handleL33tUpdate);
      socket.off("l33t_task_update", handleTaskUpdate);
      socket.off("l33t_delete_task_result");
    };
  }, [socket]);

  useEffect(() => {
    if (memoryDB) setTasks(memoryDB.tasks || {});
  }, [memoryDB]);

  const addTask = async () => {
    if (!socket) return;
    const newId = `stream_${Date.now()}`;
    const task = new L33tTask();
    
    socket.emit("l33t_add_task", newId, task);
  };

  return (
    <div className="container mx-auto pt-10">
      <div className="flex items-center gap-4 mb-4">
        <h1 className="text-3xl text-white">Tasks</h1>
        <button onClick={addTask} className="text-white" aria-label="Add Task">
          <i className="fa-plus fa-solid"></i>
        </button>
      </div>

      <div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3">
        {Object.entries(tasks).map(([taskId, task]) => {
          if (!task) return null;
          
          return (
            <div key={taskId} className="relative group">
              <Link
                to={`${taskId}`}
                className="shadow-lg bg-black bg-opacity-50 text-white p-4 rounded flex flex-col block h-full"
              >
                <div className="flex items-center justify-between mb-2">
                  <h2 className="text-xl font-bold flex items-center gap-2">
                    {taskId}
                    <div className={`w-2.5 h-2.5 rounded-full ${!(task.isStarted) ? 'bg-red-500' : 'bg-green-500'}`} />
                  </h2>
                  <button 
                    onClick={(e) => {
                      e.preventDefault();
                      e.stopPropagation();
                      toggleSelection(taskId);
                    }}
                    className="relative"
                  >
                    <i className={`fa-solid ${selectedIds.includes(taskId) ? 'fa-check-square text-blue-400' : 'fa-square text-gray-400'}`}></i>
                  </button>
                </div>

                <div className="text-sm mt-5 bg-black p-2 rounded overflow-hidden mb-8">
                  <small className="block pb-2 text-gray-400">
                    Output
                  </small>
                  {task.error ? (
                    <ErrorDisplay error={task.error} />
                  ) : (
                    <HTMLRenderer
                      html={task.lastResult || ""}
                      className="text-white break-words"
                    />
                  )}
                </div>

                <TimedStatus timed={task} />
              </Link>
            </div>
          );
        })}
      </div>
      <Outlet context={{ memoryDB }} />
    </div>
  );
}