import { useState, useEffect } from "react";
import {
  Loader2,
  Info,
  ExternalLink,
  Shield,
  CheckCircle,
  AlertCircle,
  Key,
  Lock,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from "@/components/ui/dialog";
import { Alert, AlertDescription } from "@/components/ui/alert";
import { Separator } from "@/components/ui/separator";
import { Badge } from "@/components/ui/badge";
import { useToast } from "@/components/ui/use-toast";
import { API_BASE_URL, withAgentExecutionScope } from "@/lib/api";
import { cn } from "@/lib/utils";
import type { WorkerScope } from "@/types/config";

interface ConfigField {
  name: string;
  label: string;
  type: string;
  required?: boolean;
  default?: any;
  placeholder?: string;
  description?: string;
  requiredWhenFieldChanges?: string | null;
  validation?: {
    min?: number;
    max?: number;
  };
}

type ConfigValue = string | boolean | number;

interface EnhancedConfigDialogProps {
  open: boolean;
  onClose: () => void;
  service: string;
  displayName: string;
  description: string;
  configFields: ConfigField[];
  onSuccess?: () => void;
  isEditing?: boolean;
  docsUrl?: string | null;
  helperText?: string | null;
  icon?: any;
  iconColor?: string;
  agentName?: string | null;
  executionScope?: WorkerScope | null;
}

export function EnhancedConfigDialog({
  open,
  onClose,
  service,
  displayName,
  description,
  configFields,
  onSuccess,
  isEditing = false,
  docsUrl,
  helperText,
  icon: Icon,
  iconColor,
  agentName,
  executionScope,
}: EnhancedConfigDialogProps) {
  const [configValues, setConfigValues] = useState<Record<string, ConfigValue>>(
    {},
  );
  const [existingConfigValues, setExistingConfigValues] = useState<
    Record<string, ConfigValue>
  >({});
  const [loading, setLoading] = useState(false);
  const [loadingExisting, setLoadingExisting] = useState(false);
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
  const [showPassword, setShowPassword] = useState<Record<string, boolean>>({});
  const { toast } = useToast();

  // Function to render markdown links in helper text
  const renderHelperText = (text: string) => {
    // Simple markdown link parser for [text](url)
    const parts = text.split(/(\[.*?\]\(.*?\))/g);
    return parts.map((part, index) => {
      const linkMatch = part.match(/\[(.*?)\]\((.*?)\)/);
      if (linkMatch) {
        const [, linkText, url] = linkMatch;
        return (
          <a
            key={index}
            href={url}
            target="_blank"
            rel="noopener noreferrer"
            className="text-blue-500 dark:text-blue-400 underline hover:text-blue-600 dark:hover:text-blue-300"
          >
            {linkText}
          </a>
        );
      }
      return part;
    });
  };

  // Just use the config fields as provided - no special filtering needed
  const filteredFields = configFields;

  // Initialize default values and load existing credentials
  useEffect(() => {
    if (!open) return;

    const loadExistingCredentials = async () => {
      setLoadingExisting(true);

      // Use the config fields directly
      let fieldsToUse = configFields;

      try {
        // Try to load existing credentials
        const response = await fetch(
          withAgentExecutionScope(
            `${API_BASE_URL}/api/credentials/${service}`,
            agentName,
            executionScope,
          ),
        );
        if (response.ok) {
          const data = await response.json();
          if (data.credentials) {
            // Merge existing credentials with defaults
            const defaults: Record<string, ConfigValue> = {};
            fieldsToUse.forEach((field) => {
              if (data.credentials[field.name] !== undefined) {
                if (field.type === "boolean") {
                  defaults[field.name] =
                    data.credentials[field.name] === true ||
                    data.credentials[field.name] === "true";
                } else if (field.type === "number") {
                  const numericValue = Number(data.credentials[field.name]);
                  defaults[field.name] = Number.isFinite(numericValue)
                    ? numericValue
                    : String(data.credentials[field.name]);
                } else {
                  defaults[field.name] = String(data.credentials[field.name]);
                }
              } else if (
                field.default !== undefined &&
                field.default !== null
              ) {
                // Use default value with proper type
                if (field.type === "boolean") {
                  defaults[field.name] =
                    field.default === true || field.default === "true";
                } else if (field.type === "number") {
                  const numericValue = Number(field.default);
                  defaults[field.name] = Number.isFinite(numericValue)
                    ? numericValue
                    : String(field.default);
                } else {
                  defaults[field.name] = String(field.default);
                }
              }
            });
            setConfigValues(defaults);
            setExistingConfigValues(defaults);
            setLoadingExisting(false);
            return;
          }
        }
      } catch (error) {
        console.log("No existing credentials found");
      }

      // If no existing credentials, just use defaults
      const defaults: Record<string, ConfigValue> = {};
      fieldsToUse.forEach((field) => {
        if (field.default !== undefined && field.default !== null) {
          if (field.type === "boolean") {
            defaults[field.name] =
              field.default === true || field.default === "true";
          } else if (field.type === "number") {
            const numericValue = Number(field.default);
            defaults[field.name] = Number.isFinite(numericValue)
              ? numericValue
              : String(field.default);
          } else {
            defaults[field.name] = String(field.default);
          }
        }
      });
      setConfigValues(defaults);
      setExistingConfigValues({});
      setLoadingExisting(false);
    };

    loadExistingCredentials();
  }, [service, open, configFields, agentName, executionScope]); // Use stable dependencies

  const validateField = (
    field: ConfigField,
    value: ConfigValue | undefined,
  ): string | null => {
    // Boolean fields don't need validation
    if (field.type === "boolean") {
      return null;
    }

    if (field.required && (value === undefined || value === "")) {
      return `${field.label} is required`;
    }

    if (
      field.requiredWhenFieldChanges &&
      (value === undefined || value === "")
    ) {
      const trackedField = filteredFields.find(
        (candidate) => candidate.name === field.requiredWhenFieldChanges,
      );
      const trackedFieldName = field.requiredWhenFieldChanges;
      const currentTrackedValue = configValues[trackedFieldName];
      const existingTrackedValue = existingConfigValues[trackedFieldName];
      const currentNormalized =
        typeof currentTrackedValue === "string"
          ? currentTrackedValue.trim()
          : currentTrackedValue;
      const existingNormalized =
        typeof existingTrackedValue === "string"
          ? existingTrackedValue.trim()
          : existingTrackedValue;
      if (
        existingNormalized !== undefined &&
        currentNormalized !== existingNormalized
      ) {
        return `${field.label} is required when ${trackedField?.label ?? trackedFieldName} changes`;
      }
    }

    if (value !== undefined && value !== "" && field.type === "number") {
      const numValue = Number(value);
      if (!Number.isFinite(numValue)) {
        return `${field.label} must be a number`;
      }
      if (
        field.validation?.min !== undefined &&
        numValue < field.validation.min
      ) {
        return `${field.label} must be at least ${field.validation.min}`;
      }
      if (
        field.validation?.max !== undefined &&
        numValue > field.validation.max
      ) {
        return `${field.label} must be at most ${field.validation.max}`;
      }
    }

    return null;
  };

  const handleFieldChange = (field: ConfigField, value: ConfigValue) => {
    setConfigValues({ ...configValues, [field.name]: value });

    // Clear errors for the edited field and fields whose validation depends on it.
    const dependentFieldNames = filteredFields
      .filter((candidate) => candidate.requiredWhenFieldChanges === field.name)
      .map((candidate) => candidate.name);
    if (
      fieldErrors[field.name] ||
      dependentFieldNames.some((name) => fieldErrors[name])
    ) {
      const newErrors = { ...fieldErrors };
      delete newErrors[field.name];
      dependentFieldNames.forEach((name) => {
        delete newErrors[name];
      });
      setFieldErrors(newErrors);
    }
  };

  const normalizedConfigValuesForSave = (): Record<string, ConfigValue> => {
    const normalized: Record<string, ConfigValue> = {};
    filteredFields.forEach((field) => {
      const value = configValues[field.name];
      if (field.type === "number") {
        if (value !== undefined && value !== "") {
          const numericValue = Number(value);
          if (Number.isFinite(numericValue)) {
            normalized[field.name] = numericValue;
          }
        }
      } else if (value !== undefined) {
        normalized[field.name] = value;
      }
    });
    return normalized;
  };

  const saveErrorMessage = async (response: Response): Promise<string> => {
    try {
      const data = await response.json();
      if (typeof data.detail === "string" && data.detail) {
        return data.detail;
      }
    } catch {
      // Fall back to the generic message when the response has no JSON detail.
    }
    return "Failed to save configuration";
  };

  const handleSave = async () => {
    // Validate all fields
    const errors: Record<string, string> = {};
    filteredFields.forEach((field) => {
      const error = validateField(field, configValues[field.name]);
      if (error) {
        errors[field.name] = error;
      }
    });

    if (Object.keys(errors).length > 0) {
      setFieldErrors(errors);
      toast({
        title: "Validation Error",
        description: "Please fix the errors before saving.",
        variant: "destructive",
      });
      return;
    }

    setLoading(true);
    try {
      // Save all config values as environment variables using our credentials API
      const response = await fetch(
        withAgentExecutionScope(
          `${API_BASE_URL}/api/credentials/${service}`,
          agentName,
          executionScope,
        ),
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            credentials: normalizedConfigValuesForSave(),
          }),
        },
      );

      if (!response.ok) {
        throw new Error(await saveErrorMessage(response));
      }

      toast({
        title: "Success!",
        description: `${displayName} has been ${
          isEditing ? "updated" : "configured"
        } successfully.`,
      });

      onSuccess?.();
      onClose();
    } catch (error) {
      toast({
        title: "Configuration Failed",
        description:
          error instanceof Error
            ? error.message
            : "Failed to save configuration",
        variant: "destructive",
      });
    } finally {
      setLoading(false);
    }
  };

  const getFieldIcon = (field: ConfigField) => {
    if (
      field.type === "password" ||
      field.name.toLowerCase().includes("token") ||
      field.name.toLowerCase().includes("key") ||
      field.name.toLowerCase().includes("secret")
    ) {
      return Key;
    }
    return null;
  };

  const togglePasswordVisibility = (fieldName: string) => {
    setShowPassword((prev) => ({ ...prev, [fieldName]: !prev[fieldName] }));
  };

  return (
    <Dialog open={open} onOpenChange={onClose}>
      <DialogContent className="sm:max-w-[600px]">
        <DialogHeader className="space-y-3">
          <div className="flex items-center space-x-3">
            {Icon && (
              <div className={cn("p-2 rounded-lg bg-muted", iconColor)}>
                <Icon className="h-5 w-5" />
              </div>
            )}
            <div>
              <DialogTitle className="text-xl">
                {isEditing ? "Edit" : "Configure"} {displayName}
              </DialogTitle>
              <DialogDescription className="mt-1">
                {description}
              </DialogDescription>
            </div>
          </div>

          {/* Security Notice */}
          <Alert className="border-muted">
            <Shield className="h-4 w-4" />
            <AlertDescription className="text-xs">
              Your credentials are encrypted and stored securely. They are never
              shared with third parties.
            </AlertDescription>
          </Alert>

          {/* Helper Text */}
          {helperText && (
            <Alert className="border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-950/30">
              <Info className="h-4 w-4 text-blue-600 dark:text-blue-400" />
              <AlertDescription className="text-xs text-blue-900 dark:text-blue-100">
                {renderHelperText(helperText)}
              </AlertDescription>
            </Alert>
          )}

          {/* Documentation Link - More Prominent */}
          {docsUrl && (
            <Button
              variant="outline"
              className="w-full flex items-center justify-center gap-2 bg-gradient-to-r from-orange-50 to-amber-50 dark:from-orange-950/20 dark:to-amber-950/20 hover:from-orange-100 hover:to-amber-100 dark:hover:from-orange-950/30 dark:hover:to-amber-950/30 border-orange-200 dark:border-orange-800"
              onClick={() => window.open(docsUrl, "_blank")}
            >
              <ExternalLink className="h-4 w-4" />
              View Official Documentation
            </Button>
          )}
        </DialogHeader>

        <Separator className="my-4" />

        {loadingExisting ? (
          <div className="flex flex-col items-center justify-center py-12 space-y-3">
            <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
            <p className="text-sm text-muted-foreground">
              Loading configuration...
            </p>
          </div>
        ) : (
          <>
            <div className="space-y-4 py-2 max-h-[400px] overflow-y-auto px-1">
              {filteredFields.length === 0 ? (
                <div className="flex flex-col items-center justify-center py-8 text-center">
                  <CheckCircle className="h-12 w-12 text-green-500 mb-3" />
                  <p className="text-sm text-muted-foreground">
                    This service is fully configured.
                  </p>
                  <p className="text-xs text-muted-foreground mt-1">
                    No additional configuration is required.
                  </p>
                </div>
              ) : (
                filteredFields.map((field, index) => {
                  const FieldIcon = getFieldIcon(field);
                  const isPasswordField =
                    field.type === "password" ||
                    field.name.toLowerCase().includes("token") ||
                    field.name.toLowerCase().includes("key") ||
                    field.name.toLowerCase().includes("secret");
                  const hasError = !!fieldErrors[field.name];

                  return (
                    <div key={field.name} className="space-y-2">
                      {index > 0 && <Separator className="my-4" />}

                      {field.type === "boolean" ? (
                        <div className="flex items-center space-x-3 p-3 rounded-lg hover:bg-gray-50 dark:hover:bg-white/5 transition-all duration-200">
                          <Checkbox
                            id={field.name}
                            checked={configValues[field.name] === true}
                            onCheckedChange={(checked) =>
                              handleFieldChange(field, checked === true)
                            }
                            className="h-5 w-5"
                          />
                          <label
                            htmlFor={field.name}
                            className="flex-1 cursor-pointer select-none"
                          >
                            <div className="flex items-center space-x-2">
                              {FieldIcon && (
                                <FieldIcon className="h-4 w-4 text-muted-foreground" />
                              )}
                              <span className="font-medium text-sm">
                                {field.label}
                              </span>
                              {field.required && (
                                <Badge
                                  variant="secondary"
                                  className="ml-2 text-xs px-1.5 py-0"
                                >
                                  Required
                                </Badge>
                              )}
                            </div>
                            {field.description && (
                              <div className="text-xs text-gray-500 dark:text-gray-400 mt-1 ml-6">
                                {field.description}
                              </div>
                            )}
                          </label>
                        </div>
                      ) : (
                        <>
                          <div className="space-y-1">
                            <Label
                              htmlFor={field.name}
                              className={cn(
                                "flex items-center space-x-2",
                                hasError && "text-destructive",
                              )}
                            >
                              {FieldIcon && (
                                <FieldIcon className="h-4 w-4 text-muted-foreground" />
                              )}
                              <span>{field.label}</span>
                              {field.required && (
                                <Badge
                                  variant="secondary"
                                  className="ml-2 text-xs px-1.5 py-0"
                                >
                                  Required
                                </Badge>
                              )}
                            </Label>
                            {field.description && (
                              <p className="text-xs text-muted-foreground ml-6">
                                {field.description}
                              </p>
                            )}
                          </div>
                          <div className="relative">
                            <Input
                              id={field.name}
                              type={
                                isPasswordField && !showPassword[field.name]
                                  ? "password"
                                  : field.type === "number"
                                    ? "number"
                                    : "text"
                              }
                              placeholder={field.placeholder}
                              value={String(configValues[field.name] ?? "")}
                              onChange={(e) =>
                                handleFieldChange(field, e.target.value)
                              }
                              min={field.validation?.min}
                              max={field.validation?.max}
                              className={cn(
                                "pr-10",
                                hasError &&
                                  "border-destructive focus-visible:ring-destructive",
                                isPasswordField && "font-mono",
                              )}
                            />

                            {isPasswordField && (
                              <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="absolute right-0 top-0 h-full px-3 hover:bg-transparent"
                                onClick={() =>
                                  togglePasswordVisibility(field.name)
                                }
                              >
                                {showPassword[field.name] ? (
                                  <Lock className="h-4 w-4 text-muted-foreground" />
                                ) : (
                                  <Lock className="h-4 w-4 text-muted-foreground" />
                                )}
                              </Button>
                            )}
                          </div>

                          {hasError && (
                            <div className="flex items-center space-x-1 text-destructive">
                              <AlertCircle className="h-3 w-3" />
                              <p className="text-xs">
                                {fieldErrors[field.name]}
                              </p>
                            </div>
                          )}

                          {field.validation && (
                            <p className="text-xs text-muted-foreground">
                              {field.type === "number" &&
                                field.validation.min !== undefined &&
                                field.validation.max !== undefined &&
                                `Value must be between ${field.validation.min} and ${field.validation.max}`}
                            </p>
                          )}
                        </>
                      )}
                    </div>
                  );
                })
              )}
            </div>

            <Separator className="my-4" />

            <DialogFooter className="flex items-center justify-between sm:justify-between">
              <div className="flex items-center space-x-2 text-xs text-muted-foreground">
                {isEditing ? (
                  <>
                    <Info className="h-3 w-3" />
                    <span>Updating will replace existing credentials</span>
                  </>
                ) : (
                  <>
                    <CheckCircle className="h-3 w-3" />
                    <span>Ready to configure</span>
                  </>
                )}
              </div>

              <div className="flex space-x-2">
                <Button variant="outline" onClick={onClose} disabled={loading}>
                  Cancel
                </Button>
                <Button
                  onClick={handleSave}
                  disabled={loading || Object.keys(fieldErrors).length > 0}
                  className="min-w-[120px]"
                >
                  {loading ? (
                    <>
                      <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                      Saving...
                    </>
                  ) : (
                    <>{isEditing ? "Update" : "Save"} Configuration</>
                  )}
                </Button>
              </div>
            </DialogFooter>
          </>
        )}
      </DialogContent>
    </Dialog>
  );
}
