"use client";

import {
  useCallback,
  useEffect,
  useMemo,
  useState,
  type ChangeEvent,
  type ReactElement,
  type SyntheticEvent,
} from "react";
import { FleetSettingsNav } from "@/components/settings/FleetSettingsNav";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea";
import {
  fetchFleetAgentConfig,
  fetchFleetProviders,
  updateFleetAgentConfig,
  type FleetProvider,
  type FleetProviderModel,
  type UpdateFleetAgentConfigRequest,
} from "@/lib/api/fleet-settings";

function getErrorMessage(error: unknown, fallback: string): string {
  if (error instanceof Error && error.message.trim().length > 0) {
    return error.message;
  }

  return fallback;
}

function normalizeProviderModels(models: unknown): FleetProviderModel[] {
  if (!Array.isArray(models)) {
    return [];
  }

  const parsed: FleetProviderModel[] = [];

  models.forEach((entry) => {
    if (typeof entry === "string" && entry.trim().length > 0) {
      parsed.push({ id: entry.trim(), name: entry.trim() });
      return;
    }

    if (entry && typeof entry === "object") {
      const record = entry as Record<string, unknown>;
      const id =
        typeof record.id === "string"
          ? record.id.trim()
          : typeof record.name === "string"
            ? record.name.trim()
            : "";

      if (id.length > 0) {
        parsed.push({ id, name: id });
      }
    }
  });

  const seen = new Set<string>();
  return parsed.filter((model) => {
    if (seen.has(model.id)) {
      return false;
    }

    seen.add(model.id);
    return true;
  });
}

function parseModelList(value: string): string[] {
  const seen = new Set<string>();

  return value
    .split(/\n|,/g)
    .map((segment) => segment.trim())
    .filter((segment) => segment.length > 0)
    .filter((segment) => {
      if (seen.has(segment)) {
        return false;
      }

      seen.add(segment);
      return true;
    });
}

function deriveAvailableModels(providers: FleetProvider[]): string[] {
  const seen = new Set<string>();
  const models: string[] = [];

  providers.forEach((provider) => {
    normalizeProviderModels(provider.models).forEach((model) => {
      if (seen.has(model.id)) {
        return;
      }

      seen.add(model.id);
      models.push(model.id);
    });
  });

  return models.sort((left, right) => left.localeCompare(right));
}

export default function AgentConfigSettingsPage(): ReactElement {
  const [providers, setProviders] = useState<FleetProvider[]>([]);
  const [primaryModel, setPrimaryModel] = useState<string>("");
  const [fallbackModelsText, setFallbackModelsText] = useState<string>("");
  const [personality, setPersonality] = useState<string>("");

  const [isLoading, setIsLoading] = useState<boolean>(true);
  const [isSaving, setIsSaving] = useState<boolean>(false);
  const [error, setError] = useState<string | null>(null);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);

  const availableModels = useMemo(() => deriveAvailableModels(providers), [providers]);
  const fallbackModels = useMemo(() => parseModelList(fallbackModelsText), [fallbackModelsText]);

  const modelSelectOptions = useMemo(() => {
    if (primaryModel.length > 0 && !availableModels.includes(primaryModel)) {
      return [primaryModel, ...availableModels];
    }

    return availableModels;
  }, [availableModels, primaryModel]);

  const loadSettings = useCallback(async (): Promise<void> => {
    setIsLoading(true);

    try {
      const [providerData, agentConfig] = await Promise.all([
        fetchFleetProviders(),
        fetchFleetAgentConfig(),
      ]);
      setProviders(providerData);
      setPrimaryModel(agentConfig.primaryModel ?? "");
      setFallbackModelsText(agentConfig.fallbackModels.join("\n"));
      setPersonality(agentConfig.personality ?? "");
      setError(null);
    } catch (loadError: unknown) {
      setError(getErrorMessage(loadError, "Failed to load agent configuration."));
    } finally {
      setIsLoading(false);
    }
  }, []);

  useEffect(() => {
    void loadSettings();
  }, [loadSettings]);

  function appendFallbackModel(model: string): void {
    const current = parseModelList(fallbackModelsText);
    if (current.includes(model)) {
      return;
    }

    const next = [...current, model];
    setFallbackModelsText(next.join("\n"));
  }

  async function handleSave(event: SyntheticEvent): Promise<void> {
    event.preventDefault();
    setError(null);
    setSuccessMessage(null);

    const updatePayload: UpdateFleetAgentConfigRequest = {
      personality: personality.trim(),
    };

    if (primaryModel.trim().length > 0) {
      updatePayload.primaryModel = primaryModel.trim();
    }

    const parsedFallbacks = parseModelList(fallbackModelsText).filter(
      (model) => model !== primaryModel.trim()
    );
    if (parsedFallbacks.length > 0) {
      updatePayload.fallbackModels = parsedFallbacks;
    }

    try {
      setIsSaving(true);
      await updateFleetAgentConfig(updatePayload);
      setSuccessMessage("Agent configuration saved.");
      await loadSettings();
    } catch (saveError: unknown) {
      setError(getErrorMessage(saveError, "Failed to save agent configuration."));
    } finally {
      setIsSaving(false);
    }
  }

  return (
    <div className="max-w-6xl mx-auto p-6 space-y-6">
      <div className="space-y-4">
        <div>
          <h1 className="text-3xl font-bold">Agent Configuration</h1>
          <p className="text-muted-foreground mt-1">
            Assign primary and fallback models for your agent runtime behavior.
          </p>
        </div>
        <FleetSettingsNav />
      </div>

      <Card>
        <CardHeader>
          <CardTitle>Current Assignment</CardTitle>
          <CardDescription>
            Snapshot of your currently saved model routing configuration.
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          {isLoading ? (
            <p className="text-sm text-muted-foreground">Loading configuration...</p>
          ) : (
            <>
              <div>
                <p className="text-sm font-medium">Primary Model</p>
                <p className="text-sm text-muted-foreground">
                  {primaryModel.length > 0 ? primaryModel : "No primary model configured"}
                </p>
              </div>

              <div>
                <p className="text-sm font-medium">Fallback Models</p>
                {fallbackModels.length === 0 ? (
                  <p className="text-sm text-muted-foreground">No fallback models configured</p>
                ) : (
                  <div className="flex flex-wrap gap-2 mt-2">
                    {fallbackModels.map((model) => (
                      <Badge key={`current-${model}`} variant="outline">
                        {model}
                      </Badge>
                    ))}
                  </div>
                )}
              </div>
            </>
          )}
        </CardContent>
      </Card>

      <Card>
        <CardHeader>
          <CardTitle>Update Agent Config</CardTitle>
          <CardDescription>
            Select a primary model and define fallback ordering. Models come from your provider
            settings.
          </CardDescription>
        </CardHeader>
        <CardContent>
          <form onSubmit={(event) => void handleSave(event)} className="space-y-5">
            <div className="space-y-2">
              <Label htmlFor="primary-model">Primary Model</Label>
              <Select
                value={primaryModel.length > 0 ? primaryModel : "__none__"}
                onValueChange={(value) => {
                  setPrimaryModel(value === "__none__" ? "" : value);
                }}
                disabled={isLoading || isSaving}
              >
                <SelectTrigger id="primary-model">
                  <SelectValue placeholder="Select a primary model" />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="__none__">No primary model selected</SelectItem>
                  {modelSelectOptions.map((model) => (
                    <SelectItem key={model} value={model}>
                      {model}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              {availableModels.length === 0 ? (
                <p className="text-xs text-muted-foreground">
                  No models available yet. Add provider models first in Providers settings.
                </p>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="fallback-models">Fallback Models</Label>
              <Textarea
                id="fallback-models"
                value={fallbackModelsText}
                onChange={(event: ChangeEvent<HTMLTextAreaElement>) => {
                  setFallbackModelsText(event.target.value);
                }}
                rows={4}
                placeholder={"One model per line\nExample: gpt-4.1-mini"}
                disabled={isLoading || isSaving}
              />
              {availableModels.length > 0 ? (
                <div className="flex flex-wrap gap-2">
                  {availableModels
                    .filter((model) => model !== primaryModel)
                    .map((model) => (
                      <Button
                        key={`suggest-${model}`}
                        type="button"
                        variant="outline"
                        size="sm"
                        onClick={() => {
                          appendFallbackModel(model);
                        }}
                        disabled={fallbackModels.includes(model) || isSaving}
                      >
                        {fallbackModels.includes(model) ? `Added: ${model}` : `Add ${model}`}
                      </Button>
                    ))}
                </div>
              ) : null}
            </div>

            <div className="space-y-2">
              <Label htmlFor="agent-personality">Personality / SOUL</Label>
              <Textarea
                id="agent-personality"
                value={personality}
                onChange={(event: ChangeEvent<HTMLTextAreaElement>) => {
                  setPersonality(event.target.value);
                }}
                rows={8}
                placeholder="Optional system personality instructions..."
                disabled={isLoading || isSaving}
              />
            </div>

            {error ? (
              <p className="text-sm text-destructive" role="alert">
                {error}
              </p>
            ) : null}

            {successMessage ? <p className="text-sm text-emerald-600">{successMessage}</p> : null}

            <Button type="submit" disabled={isLoading || isSaving}>
              {isSaving ? "Saving..." : "Save Agent Config"}
            </Button>
          </form>
        </CardContent>
      </Card>
    </div>
  );
}
