import { useDataSources, useUpdateDataSources, useTestDataSource, useRegisteredProviders } from "@/hooks/useConfig"
import { DataSourceConfig, DataSourceProvider, DataSourceProviders } from "@/types/config"
import { useToast } from "@/hooks/use-toast"
import { DynamicConfigForm } from "@/components/config/DynamicConfigForm"

export function DataSourceTab() {
  const { data: dataSources, isLoading: isConfigLoading } = useDataSources();
  const { data: providersMetadata, isLoading: isMetadataLoading } = useRegisteredProviders();
  
  const updateDataSources = useUpdateDataSources();
  const testDataSource = useTestDataSource();
  const { toast } = useToast();

  if (isConfigLoading || isMetadataLoading) {
    return <div>Loading data sources...</div>;
  }

  if (!providersMetadata || providersMetadata.length === 0) {
      return (
          <div className="p-4 text-center text-muted-foreground">
              No data providers registered. Please ensure provider services are running.
          </div>
      );
  }

  const handleSave = (providerId: string, config: DataSourceConfig) => {
      // We need to reconstruct the full DataSourcesConfig map
      // Note: dataSources is a HashMap<String, DataSourceConfig>
      const newDataSources = { ...dataSources, [providerId]: config };
      updateDataSources.mutate(newDataSources, {
          onSuccess: () => toast({ title: "Success", description: `${providerId} configuration saved` }),
          onError: (err) => toast({ title: "Error", description: "Failed to save: " + err, type: "error" })
      });
  };

  const handleTest = (providerId: string, config: DataSourceConfig) => {
      // Construct payload for generic test endpoint
      const payload = {
          type: providerId, 
          data: config // Send the whole config object as data
      };

      // We cast to any because TestConfigRequest type definition in frontend might be loose or generic
      testDataSource.mutate(payload as any, {
          onSuccess: (data: any) => {
            console.log("Test Connection Success Payload:", data);
            // Check both explicit false and explicit "false" string, or any other falsy indicator
            if (data.success === false || data.success === "false") {
                console.warn("Test reported success but payload indicates failure:", data);
                toast({ 
                    title: "Test Failed", 
                    description: data.message || "Connection test failed",
                    type: "error" 
                });
            } else {
                console.log("Test confirmed successful.");
                toast({ 
                    title: "Success", 
                    description: data.message || "Connection test successful" 
                });
            }
          },
          onError: (err: any) => {
            console.error("Test Connection Error:", err);
            let errorMessage = "Connection test failed";
            
            if (err.response?.data) {
                const data = err.response.data;
                console.log("Error Response Data:", data);
                // Try to parse 'details' if it exists and is a string (common-contracts error format)
                if (typeof data.details === 'string') {
                    try {
                        const parsed = JSON.parse(data.details);
                        if (parsed.message) errorMessage = parsed.message;
                        else errorMessage = data.details;
                    } catch (e) {
                        errorMessage = data.details;
                    }
                } else if (data.message) {
                    errorMessage = data.message;
                } else if (data.error) {
                    errorMessage = data.error;
                }
            }
            
            toast({ 
                title: "Test Failed", 
                description: errorMessage, 
                type: "error" 
            });
          }
      });
  };

  return (
    <div className="grid gap-6 md:grid-cols-1 lg:grid-cols-2">
      {providersMetadata.map(meta => {
        // Find existing config or create default
        const configEntry = dataSources ? (dataSources as Record<string, any>)[meta.id] : undefined;

        // We know that meta.id must be a valid DataSourceProvider because the backend
        // only registers providers that are part of the enum system.
        // However, meta.id comes as lowercase (e.g., "tushare") while the Enum expects PascalCase (e.g., "Tushare").
        // To maintain strict type safety and follow the Single Source of Truth,
        // we need to cast or map it correctly. 
        // Since we cannot change the backend serialization easily without breaking other things,
        // and we must respect the Zod schema, we try to match it case-insensitively to the Enum.

        let providerEnum = Object.values(DataSourceProviders).find(
            (p) => p.toLowerCase() === meta.id.toLowerCase()
        );

        if (!providerEnum) {
            console.warn(`Provider ID '${meta.id}' from metadata does not match any known DataSourceProvider enum.`);
            // Fallback or skip? If we skip, the user can't configure it. 
            // If we cast forcefully, Zod might reject it on save.
            // Let's attempt to use it as is but cast to satisfy TS, acknowledging the risk if it doesn't match.
            providerEnum = meta.id as DataSourceProvider;
        }
        
        const config = (configEntry || {
            provider: providerEnum,
            enabled: false,
            // We init other fields as empty, they will be filled by DynamicConfigForm
        }) as DataSourceConfig;

        return (
            <DynamicConfigForm 
                key={meta.id}
                metadata={meta}
                initialConfig={config}
                onSave={(c) => handleSave(meta.id, c)}
                onTest={(c) => handleTest(meta.id, c)}
                isSaving={updateDataSources.isPending}
                isTesting={testDataSource.isPending}
            />
        )
      })}
    </div>
  )
}
