import React, { useState, useEffect } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";

import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Link,
  Download,
  Eye,
  Upload,
  Hash,
  FileText,
  Database,
  Calendar,
} from "lucide-react";
import { useModal } from "@/context/ModalContext";
import { useToast } from "@/hooks/use-toast";
import { useNavigation } from "@/context/NavigationContext";
import { useAgentGraph } from "@/context/AgentGraphContext";
import { api } from "@/lib/api";
import langfuseIcon from "@/static/langfuse.png";
import langsmithIcon from "@/static/langsmith.png";
import { PreprocessingMethodModal } from "@/components/shared/modals/PreprocessingMethodModal";

interface Connection {
  id: string;
  platform: string;
  status: string;
  connected_at: string;
  last_sync: string | null;
  projects: Array<{
    id: string;
    name: string;
    description?: string;
    created_at?: string;
  }>;
}

interface FetchedTrace {
  id: string;
  name: string;
  platform: string;
  fetched_at: string;
  generated_timestamp?: string;
  imported: boolean;
  data?: any;
  connection_id?: string;
}

export function ConnectionsView() {
  const [connections, setConnections] = useState<Connection[]>([]);
  const [fetchedTraces, setFetchedTraces] = useState<FetchedTrace[]>([]);
  const [selectedTraces, setSelectedTraces] = useState<Set<string>>(new Set());
  const [fetchingConnections, setFetchingConnections] = useState<Set<string>>(
    new Set()
  );
  const [selectedProjects, setSelectedProjects] = useState<Map<string, string>>(
    new Map()
  );
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [connectionToDelete, setConnectionToDelete] =
    useState<Connection | null>(null);
  const [previewDialogOpen, setPreviewDialogOpen] = useState(false);
  const [previewTrace, setPreviewTrace] = useState<FetchedTrace | null>(null);
  const [preprocessingModalOpen, setPreprocessingModalOpen] = useState(false);
  const [tracesToImport, setTracesToImport] = useState<FetchedTrace[]>([]);
  const [isImporting, setIsImporting] = useState(false);
  const { openModal } = useModal();
  const { toast } = useToast();
  const { actions: navigationActions } = useNavigation();
  const { actions: agentGraphActions } = useAgentGraph();

  const loadConnections = async () => {
    try {
      const response = await api.observability.getConnections();
      setConnections(
        response.connections.map((conn: any) => ({
          ...conn,
          last_sync: null, // Add missing field
          projects: conn.projects || [], // Add projects field
        })) || []
      );

      // Load fetched traces for each connection using connection-specific API
      const allFetchedTraces: FetchedTrace[] = [];
      for (const conn of response.connections) {
        try {
          const fetchedResponse = await api.observability.getFetchedTracesByConnection(
            conn.id
          );
          const tracesWithConnectionId = fetchedResponse.traces.map((trace: any) => ({
            ...trace,
            connection_id: conn.id
          }));
          allFetchedTraces.push(...tracesWithConnectionId);
        } catch (error) {
          console.warn(
            `Failed to load fetched traces for connection ${conn.id}:`,
            error
          );
        }
      }
      setFetchedTraces(allFetchedTraces);
    } catch (error) {
      console.warn("Failed to load connections:", error);
      setConnections([]);
    }
  };

  useEffect(() => {
    loadConnections();
  }, []);

  useEffect(() => {
    const handleConnectionUpdate = () => {
      loadConnections();
    };

    window.addEventListener(
      "observability-connection-updated",
      handleConnectionUpdate
    );

    return () => {
      window.removeEventListener(
        "observability-connection-updated",
        handleConnectionUpdate
      );
    };
  }, []);

  // Auto-select first project for connections that don't have a project selected
  useEffect(() => {
    if (connections.length > 0) {
      const newSelected = new Map(selectedProjects);
      let hasChanges = false;
      
      connections.forEach(connection => {
        if (!selectedProjects.has(connection.id) && connection.projects && connection.projects.length > 0) {
          const firstProject = connection.projects[0];
          if (firstProject?.name) {
            newSelected.set(connection.id, firstProject.name);
            hasChanges = true;
          }
        }
      });
      
      if (hasChanges) {
        setSelectedProjects(newSelected);
      }
    }
  }, [connections, selectedProjects]);

  const handleAddConnection = () => {
    openModal("observability-connection", "Connect to AI Observability");
  };

  const handleEditConnection = (connection: Connection) => {
    openModal(
      "observability-connection",
      `Edit ${connection.platform} Connection`,
      {
        editConnection: connection,
      }
    );
  };

  const handleDeleteConnection = async (connection: Connection) => {
    setConnectionToDelete(connection);
    setDeleteDialogOpen(true);
  };

  const confirmDelete = async () => {
    if (!connectionToDelete) return;

    try {
      await api.observability.deleteConnection(connectionToDelete.id);
      loadConnections();
      setDeleteDialogOpen(false);
      setConnectionToDelete(null);
    } catch (error) {
      console.error("Failed to delete connection:", error);
    }
  };

  const cancelDelete = () => {
    setDeleteDialogOpen(false);
    setConnectionToDelete(null);
  };

  const handleFetchTraces = async (connectionId: string, projectName?: string) => {
    setFetchingConnections((prev) => new Set(prev).add(connectionId));
    try {
      // Get the connection to find project info
      const connection = connections.find(conn => conn.id === connectionId);
      const selectedProjectName = selectedProjects.get(connectionId) || projectName;
      let projectId: string | undefined;
      
      if (connection && selectedProjectName) {
        const selectedProject = connection.projects.find(p => p.name === selectedProjectName);
        projectId = selectedProject?.id;
      }

      // Trigger fetch from specific connection with project info
      await api.observability.fetchTracesByConnection(connectionId, 50, projectId, selectedProjectName);

      // Reload all traces to ensure consistency
      loadConnections();
    } catch (error) {
      console.error("Failed to fetch traces:", error);
    } finally {
      setFetchingConnections((prev) => {
        const newSet = new Set(prev);
        newSet.delete(connectionId);
        return newSet;
      });
    }
  };

  const handleDownloadTrace = async (trace: FetchedTrace) => {
    try {
      // Much simpler! Just need the trace ID
      const response = await api.observability.downloadTrace(trace.id);
      const jsonContent = JSON.stringify(response.data, null, 2);

      // Create blob and download
      const blob = new Blob([jsonContent], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `${trace.name}_${trace.platform}.json`;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);

      toast({
        title: "Download Complete",
        description: `${trace.name} has been downloaded successfully.`,
      });
    } catch (error) {
      console.error("Error downloading trace:", error);
      toast({
        title: "Download Failed",
        description: "Failed to download trace. Please try again.",
        variant: "destructive",
      });
    }
  };

  const handleBulkImport = async () => {
    const selectedTracesToImport = fetchedTraces.filter(
      (t) => selectedTraces.has(t.id) && !t.imported
    );

    if (selectedTracesToImport.length === 0) return;

    // Store traces to import and show preprocessing method modal
    setTracesToImport(selectedTracesToImport);
    setPreprocessingModalOpen(true);
  };

  const handlePreprocessingMethodConfirm = async (preprocessingOptions: {
    max_char: number | null;
    topk: number;
    raw: boolean;
    hierarchy: boolean;
    replace: boolean;
  }) => {
    setIsImporting(true);
    setPreprocessingModalOpen(false);

    const successfulImports: string[] = [];
    const failedImports: string[] = [];

    try {
      // Process each trace by uploading the preprocessed data
      for (const trace of tracesToImport) {
        try {
          console.log(
            `Processing trace ${trace.id} from ${trace.platform} with preprocessing options:`, preprocessingOptions
          );

          // Find the connection for this trace
          const connection = connections.find(conn => conn.id === trace.connection_id);
          if (!connection) {
            throw new Error(`No connection found for trace ${trace.id}`);
          }

          // Call backend import API using connection-specific endpoint
          const result = await api.observability.importTracesByConnection(
            connection.id,
            [trace.id],
            preprocessingOptions
          );

          if (result.imported > 0) {
            successfulImports.push(trace.id);
            console.log(`Successfully processed trace ${trace.id}`);
          } else {
            failedImports.push(trace.id);
            console.log(`Failed to process trace ${trace.id}:`, result.errors);
          }
        } catch (error) {
          console.error(`Failed to process trace ${trace.id}:`, error);
          failedImports.push(trace.id);
        }
      }

      // Update UI state for successfully imported traces
      if (successfulImports.length > 0) {
        setFetchedTraces((prev) =>
          prev.map((t) =>
            successfulImports.includes(t.id) ? { ...t, imported: true } : t
          )
        );
      }

      // Clear selection
      setSelectedTraces(new Set());

      // Refresh traces list after successful import
      if (successfulImports.length > 0) {
        try {
          const tracesData = await api.traces.list();
          // Update traces in AgentGraphContext
          agentGraphActions.setTraces(
            Array.isArray(tracesData) ? tracesData : []
          );
        } catch (error) {
          console.error("Failed to refresh traces list:", error);
        }
      }

      // Show appropriate toast based on results
      if (successfulImports.length > 0 && failedImports.length === 0) {
        toast({
          title: "Traces Imported Successfully",
          description: `${successfulImports.length} trace${
            successfulImports.length > 1 ? "s" : ""
          } imported to your traces.`,
          variant: "default",
        });

        // Navigate to main page (traces section) only if all imports succeeded
        navigationActions.setCurrentSection("traces");
      } else if (successfulImports.length > 0 && failedImports.length > 0) {
        toast({
          title: "Partial Import Success",
          description: `${successfulImports.length} traces imported successfully, ${failedImports.length} failed.`,
          variant: "default",
        });
      } else {
        toast({
          title: "Import Failed",
          description:
            "Failed to import all selected traces. Please try again.",
          variant: "destructive",
        });
      }
    } catch (error) {
      console.error("Failed to import traces:", error);
      toast({
        title: "Import Failed",
        description: "Failed to import traces. Please try again.",
        variant: "destructive",
      });
    } finally {
      setIsImporting(false);
      setTracesToImport([]);
    }
  };

  const handlePreprocessingMethodCancel = () => {
    setPreprocessingModalOpen(false);
    setTracesToImport([]);
  };

  const handlePreviewTrace = (trace: FetchedTrace) => {
    setPreviewTrace(trace);
    setPreviewDialogOpen(true);
  };

  const getPlatformIcon = (platform: string) => {
    switch (platform.toLowerCase()) {
      case "langfuse":
        return (
          <img
            src={langfuseIcon}
            alt="Langfuse"
            className="h-6 w-6 object-contain"
          />
        );
      case "langsmith":
        return (
          <img
            src={langsmithIcon}
            alt="LangSmith"
            className="h-6 w-6 object-contain"
          />
        );
      default:
        return "AI";
    }
  };

  if (connections.length === 0) {
    return (
      <div className="flex-1 flex flex-col items-center justify-center p-8">
        <div className="text-center space-y-6 max-w-md">
          <div className="h-16 w-16 rounded-full bg-primary/10 flex items-center justify-center mx-auto">
            <Link className="h-8 w-8 text-primary" />
          </div>
          <div className="space-y-2">
            <h2 className="text-2xl font-bold">Connect AI Observability</h2>
            <p className="text-muted-foreground">
              Connect to your AI observability platforms to fetch and import
              traces
            </p>
          </div>
          <Button onClick={handleAddConnection} size="lg" className="gap-2">
            <Link className="h-4 w-4" />
            Add Connection
          </Button>
        </div>
      </div>
    );
  }

  return (
    <>
      <div className="flex-1 p-6 space-y-6 overflow-y-auto">
        {/* Header */}
        <div className="flex items-center justify-between">
          <div>
            <h1 className="text-2xl font-bold">Connections</h1>
            <p className="text-muted-foreground">
              Manage your AI observability platform connections
            </p>
          </div>
          <Button onClick={handleAddConnection} className="gap-2">
            <Link className="h-4 w-4" />
            Add Connection
          </Button>
        </div>

        {/* Platform Connection Cards */}
        <div className="space-y-6">
          {connections.map((connection) => {
            const isFetching = fetchingConnections.has(connection.id);
            const selectedProject = selectedProjects.get(connection.id);
            const connectionTraces = fetchedTraces.filter(
              (trace) => trace.connection_id === connection.id
            );
            const connectionSelectedTraces = new Set(
              Array.from(selectedTraces).filter((id) =>
                connectionTraces.some((trace) => trace.id === id)
              )
            );

            return (
              <Card key={connection.id} className="overflow-hidden">
                <CardContent className="p-6">
                  {/* Connection Header */}
                  <div className="flex items-center justify-between mb-4">
                    <div className="flex items-center gap-3">
                      <div className="h-10 w-10 rounded-lg bg-primary/10 flex items-center justify-center">
                        {getPlatformIcon(connection.platform)}
                      </div>
                      <div>
                        <h3 className="text-lg font-semibold capitalize">
                          {connection.platform === "langfuse"
                            ? "Langfuse"
                            : "LangSmith"}
                        </h3>
                        <p className="text-sm text-muted-foreground">
                          Connected{" "}
                          {new Date(
                            connection.connected_at
                          ).toLocaleDateString()}
                        </p>
                      </div>
                    </div>
                    <div className="flex items-center gap-2">
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => handleEditConnection(connection)}
                      >
                        Edit
                      </Button>
                      <Button
                        variant="outline"
                        size="sm"
                        onClick={() => handleDeleteConnection(connection)}
                      >
                        Delete
                      </Button>
                    </div>
                  </div>

                  {/* Fetch Controls */}
                  <div className="space-y-4 mb-6">
                    <div className="flex items-center gap-3">
                      {/* Project Selection */}
                      {connection.projects &&
                        connection.projects.length > 0 && (
                          <div className="flex-1">
                            <label className="text-sm font-medium text-muted-foreground mb-2 block">
                              Select Project
                            </label>
                            <select
                              value={
                                selectedProject ||
                                connection.projects[0]?.name ||
                                ""
                              }
                              onChange={(e) => {
                                const newSelected = new Map(selectedProjects);
                                newSelected.set(connection.id, e.target.value);
                                setSelectedProjects(newSelected);
                              }}
                              className="w-full px-3 py-2 text-sm border border-gray-300 rounded-md bg-white"
                              disabled={isFetching}
                            >
                              {connection.projects.map((project) => (
                                <option key={project.id} value={project.name}>
                                  {project.name}
                                </option>
                              ))}
                            </select>
                          </div>
                        )}

                      {/* Fetch Button */}
                      <div className="flex-1">
                        <label className="text-sm font-medium text-muted-foreground mb-2 block">
                          Fetch Traces
                        </label>
                        <Button
                          onClick={() =>
                            handleFetchTraces(
                              connection.id,
                              selectedProject
                            )
                          }
                          disabled={isFetching}
                          className="w-full"
                        >
                          {isFetching ? (
                            <>
                              <div className="h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent mr-2" />
                              Fetching...
                            </>
                          ) : (
                            <>
                              <Download className="h-4 w-4 mr-2" />
                              Fetch Traces
                            </>
                          )}
                        </Button>
                      </div>
                    </div>
                  </div>

                  {/* Connection Fetched Traces */}
                  {connectionTraces.length > 0 && (
                    <div className="space-y-4">
                      <div className="flex items-center justify-between">
                        <h4 className="text-md font-semibold">
                          Fetched Traces ({connectionTraces.length})
                        </h4>
                        <div className="flex items-center gap-2">
                          {/* Import All Button */}
                          <Button
                            size="sm"
                            variant="outline"
                            onClick={() => {
                              // Import all non-imported traces without changing selection
                              const tracesToImportAll = connectionTraces.filter(
                                (trace) => !trace.imported
                              );
                              
                              if (tracesToImportAll.length === 0) return;
                              
                              // Store traces to import and show preprocessing method modal
                              setTracesToImport(tracesToImportAll);
                              setPreprocessingModalOpen(true);
                            }}
                            disabled={connectionTraces.every(
                              (trace) => trace.imported
                            )}
                            title="Import all traces"
                          >
                            <Upload className="h-3 w-3 mr-1" />
                            Import All (
                            {connectionTraces.filter((t) => !t.imported).length})
                          </Button>

                          {/* Import Selected Button */}
                          <Button
                            size="sm"
                            onClick={handleBulkImport}
                            disabled={
                              connectionSelectedTraces.size === 0 ||
                              !Array.from(connectionSelectedTraces).some(
                                (id) =>
                                  !connectionTraces.find((t) => t.id === id)
                                    ?.imported
                              )
                            }
                            title="Import selected traces"
                          >
                            <Upload className="h-3 w-3 mr-1" />
                            Import Selected ({connectionSelectedTraces.size})
                          </Button>
                        </div>
                      </div>

                      <div className="border rounded-lg overflow-hidden">
                        <div className="overflow-x-auto">
                          <table className="w-full">
                            <thead>
                              <tr className="border-b bg-muted/50">
                                <th className="text-left p-3 font-medium">
                                  <input
                                    type="checkbox"
                                    className="mr-2"
                                    onChange={(e) => {
                                      const newSelected = new Set(
                                        selectedTraces
                                      );
                                      if (e.target.checked) {
                                        connectionTraces.forEach((trace) =>
                                          newSelected.add(trace.id)
                                        );
                                      } else {
                                        connectionTraces.forEach((trace) =>
                                          newSelected.delete(trace.id)
                                        );
                                      }
                                      setSelectedTraces(newSelected);
                                    }}
                                    checked={
                                      connectionTraces.length > 0 &&
                                      connectionTraces.every((trace) =>
                                        selectedTraces.has(trace.id)
                                      )
                                    }
                                  />
                                  Name
                                </th>
                                <th className="text-left p-3 font-medium">
                                  Fetch Time
                                </th>
                                <th className="text-left p-3 font-medium">
                                  Generated At
                                </th>
                                <th className="text-left p-3 font-medium">
                                  Actions
                                </th>
                              </tr>
                            </thead>
                            <tbody>
                              {connectionTraces.map((trace) => (
                                <tr
                                  key={trace.id}
                                  className="border-b hover:bg-muted/20"
                                >
                                  <td className="p-3">
                                    <div className="flex items-center gap-2">
                                      <input
                                        type="checkbox"
                                        checked={selectedTraces.has(trace.id)}
                                        onChange={(e) => {
                                          const newSelected = new Set(
                                            selectedTraces
                                          );
                                          if (e.target.checked) {
                                            newSelected.add(trace.id);
                                          } else {
                                            newSelected.delete(trace.id);
                                          }
                                          setSelectedTraces(newSelected);
                                        }}
                                      />
                                      <span className="font-medium">
                                        {trace.name}
                                      </span>
                                      {trace.imported && (
                                        <span className="text-xs bg-green-100 text-green-800 px-2 py-1 rounded">
                                          Imported
                                        </span>
                                      )}
                                    </div>
                                  </td>
                                  <td className="p-3 text-sm text-muted-foreground">
                                    {new Date(
                                      trace.fetched_at
                                    ).toLocaleString()}
                                  </td>
                                  <td className="p-3 text-sm text-muted-foreground">
                                    {trace.generated_timestamp
                                      ? new Date(
                                          trace.generated_timestamp
                                        ).toLocaleString()
                                      : new Date(
                                          trace.fetched_at
                                        ).toLocaleString()}
                                  </td>
                                  <td className="p-3">
                                    <div className="flex items-center gap-1">
                                      <Button
                                        variant="outline"
                                        size="sm"
                                        onClick={() =>
                                          handlePreviewTrace(trace)
                                        }
                                      >
                                        <Eye className="h-3 w-3" />
                                      </Button>
                                      <Button
                                        size="sm"
                                        onClick={() =>
                                          handleDownloadTrace(trace)
                                        }
                                        variant="outline"
                                        title="Download JSON"
                                      >
                                        <Download className="h-3 w-3" />
                                      </Button>
                                    </div>
                                  </td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>
                      </div>
                    </div>
                  )}
                </CardContent>
              </Card>
            );
          })}
        </div>
      </div>

      {/* Delete Confirmation Dialog */}
      <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Delete Connection</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete the {connectionToDelete?.platform}{" "}
              connection? This action cannot be undone.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={cancelDelete}>
              Cancel
            </Button>
            <Button variant="destructive" onClick={confirmDelete}>
              Delete
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Preview Trace Dialog */}
      <Dialog open={previewDialogOpen} onOpenChange={setPreviewDialogOpen}>
        <DialogContent className="max-w-4xl max-h-[80vh] overflow-hidden">
          <DialogHeader>
            <DialogTitle>Preview {previewTrace?.name}</DialogTitle>
            <DialogDescription>
              {previewTrace?.platform} trace data
            </DialogDescription>
          </DialogHeader>

          {/* Content Statistics */}
          {previewTrace && (
            <div className="px-4 py-2 bg-muted/50 rounded-lg border">
              <div className="flex flex-wrap items-center gap-4 text-sm text-muted-foreground">
                <span className="flex items-center gap-1 flex-shrink-0">
                  <Hash className="h-4 w-4" />
                  {JSON.stringify(
                    previewTrace.data,
                    null,
                    2
                  ).length.toLocaleString()}{" "}
                  characters
                </span>
                <span className="flex items-center gap-1 flex-shrink-0">
                  <FileText className="h-4 w-4" />
                  {JSON.stringify(previewTrace.data, null, 2)
                    .split("\n")
                    .length.toLocaleString()}{" "}
                  lines
                </span>
                <span className="flex items-center gap-1 flex-shrink-0">
                  <Database className="h-4 w-4" />
                  {(() => {
                    const content = JSON.stringify(previewTrace.data, null, 2);
                    const wordCount = content.trim()
                      ? content.trim().split(/\s+/).length
                      : 0;
                    return wordCount.toLocaleString();
                  })()}{" "}
                  words
                </span>
                <span className="flex items-center gap-1 flex-shrink-0">
                  <Calendar className="h-4 w-4" />
                  <span className="truncate max-w-40">
                    {previewTrace.generated_timestamp
                      ? new Date(
                          previewTrace.generated_timestamp
                        ).toLocaleString()
                      : new Date(previewTrace.fetched_at).toLocaleString()}
                  </span>
                </span>
              </div>
            </div>
          )}

          <div className="flex-1 overflow-hidden">
            <pre className="bg-muted p-4 rounded-md text-sm overflow-auto max-h-[50vh] whitespace-pre-wrap">
              {previewTrace ? JSON.stringify(previewTrace.data, null, 2) : ""}
            </pre>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => setPreviewDialogOpen(false)}
            >
              Close
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Preprocessing Method Selection Modal */}
      <PreprocessingMethodModal
        open={preprocessingModalOpen}
        onOpenChange={setPreprocessingModalOpen}
        onConfirm={handlePreprocessingMethodConfirm}
        onCancel={handlePreprocessingMethodCancel}
        isLoading={isImporting}
      />
    </>
  );
}
