/**
 * Modify Modal Component
 * Modal for modifying an instance configuration
 * Supports Values Schema for dynamic form generation
 */
import React, { useState, useEffect } from "react";
import { Settings } from "lucide-react";
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
import type { InstanceResponse, UpdateInstanceRequest } from "@/api";
import { getInstance, getInstanceValuesDiff } from "@/api";
import {
  Modal,
  Button,
  FormField,
  Input,
  Textarea,
  ErrorState,
  LoadingState,
  Badge,
} from "@/shared/components";

interface ModifyModalProps {
  instance: InstanceResponse;
  onClose: () => void;
  onConfirm: (clusterId: string, instanceId: string, data: UpdateInstanceRequest) => Promise<void>;
}

export const ModifyModal: React.FC<ModifyModalProps> = ({
  instance,
  onClose,
  onConfirm,
}) => {
  const [tag, setTag] = useState("");
  const [description, setDescription] = useState("");
  const [valuesYaml, setValuesYaml] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [modifiedKeys, setModifiedKeys] = useState<string[]>([]);

  // Values Diff support
  const [showDiff, setShowDiff] = useState(false);
  const [loadingDiff] = useState(false);
  const [diffData, setDiffData] = useState<{
    current: Record<string, any>;
    defaults: Record<string, any>;
  } | null>(null);
  const [diffError] = useState<string | null>(null);

  // Fetch full Helm values (via values-diff API) and instance detail
  useEffect(() => {
    setTag(instance.version || "");
    setDescription("");

    const loadData = async () => {
      if (instance.clusterId && instance.id) {
        // Load values diff first — gives us the full current Helm values
        try {
          const data = await getInstanceValuesDiff(instance.clusterId, instance.id);
          if (data?.current && Object.keys(data.current).length > 0) {
            const currentYaml = stringifyYaml(data.current, { lineWidth: 0 });
            setValuesYaml(currentYaml);
            setDiffData({ current: data.current, defaults: data.defaults ?? {} });
          }
        } catch (err) {
          console.error('[ModifyModal] Failed to load values diff:', err);
          // Fallback: try instance detail
          try {
            const detail = await getInstance({ clusterId: instance.clusterId, instanceId: instance.id });
            if (detail.values && Object.keys(detail.values).length > 0) {
              const y = stringifyYaml(detail.values, { lineWidth: 0 });
              setValuesYaml(y);
            }
          } catch (err2) {
            console.error('[ModifyModal] Failed to load instance detail:', err2);
          }
        }
      }
    };

    loadData();
  }, [instance]);

  // Recompute modified keys when valuesYaml or diffData changes
  useEffect(() => {
    if (!diffData?.defaults || !valuesYaml) return;
    try {
      const current = parseYaml(valuesYaml);
      const defaults = diffData.defaults;
      const changed: string[] = [];
      const walkKeys = (curr: any, def: any, prefix: string) => {
        if (curr === null || curr === undefined) return;
        if (typeof curr !== 'object') return;
        for (const key of Object.keys(curr)) {
          const fullKey = prefix ? `${prefix}.${key}` : key;
          if (JSON.stringify(curr[key]) !== JSON.stringify(def?.[key])) {
            changed.push(fullKey);
          }
          if (typeof curr[key] === 'object' && curr[key] !== null && !Array.isArray(curr[key])) {
            walkKeys(curr[key], def?.[key] ?? {}, fullKey);
          }
        }
      };
      walkKeys(current, defaults, '');
      setModifiedKeys(changed);
    } catch { /* ignore parse errors */ }
  }, [valuesYaml, diffData]);


  const applyDefaults = () => {
    if (!diffData?.defaults) return;
    setValuesYaml(stringifyYaml(diffData.defaults, { lineWidth: 0 }));
  };

  /**
   * Render a values object as YAML lines, bolding keys that differ from defaults.
   */
  const renderDiffValues = (
    values: Record<string, any>,
    compare: Record<string, any>,
  ): React.ReactNode => {
    const yaml = stringifyYaml(values);
    const lines = yaml.split("\n");
    return lines.map((line, i) => {
      // Extract the key name from a YAML line
      const keyMatch = line.match(/^(\s*)([a-zA-Z_][\w-]*)\s*:/);
      if (keyMatch) {
        const key = keyMatch[2];
        const keyChanged =
          compare[key] !== undefined &&
          JSON.stringify(values[key]) !== JSON.stringify(compare[key]);
        if (keyChanged) {
          return (
            <span key={i} className="block">
              {keyMatch[1]}<strong className="text-amber-600 dark:text-amber-400">{key}</strong>:{line.slice(keyMatch[0].length)}
            </span>
          );
        }
      }
      return <span key={i} className="block">{line}</span>;
    });
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError(null);

    try {
      if (valuesYaml.trim()) {
        parseValuesYaml(valuesYaml);
      }
      const payload: UpdateInstanceRequest = {
        version: tag && tag !== instance.version ? tag : undefined,
        description: description.trim() || undefined,
        valuesYaml: valuesYaml.trim() || undefined,
      };

      if (!instance.clusterId || !instance.id) {
        setError("Instance identifier is missing");
        setLoading(false);
        return;
      }

      await onConfirm(instance.clusterId, instance.id, payload);
      onClose();
    } catch (err: unknown) {
      if (err instanceof Error && err.message.includes("YAML")) {
        setError(err.message);
      } else {
        setError((err as Error).message || "Failed to modify instance");
      }
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal
      open={true}
      onClose={onClose}
      title={`Modify Instance - ${instance.name || "Unnamed"}`}
      icon={Settings}
      iconColor="text-blue-600"
      size="lg"
      footer={
        <>
          <Button
            type="button"
            variant="secondary"
            onClick={onClose}
            disabled={loading}
          >
            Cancel
          </Button>
          <Button
            type="submit"
            variant="primary"
            icon={Settings}
            loading={loading}
            onClick={handleSubmit}
          >
            {loading ? "Modifying..." : "Modify"}
          </Button>
        </>
      }
    >
      <form onSubmit={handleSubmit} className="space-y-4">
        {/* Error Alert */}
        {error && (
          <ErrorState message={error} title="Modification Failed" />
        )}

        {/* Current Info */}
        <div className="bg-slate-50 border border-slate-200 rounded-lg p-4 space-y-2">
          <p className="text-sm text-slate-700">
            <span className="font-medium text-slate-900">Current Version:</span> {instance.version || "N/A"}
          </p>
          <p className="text-sm text-slate-700">
            <span className="font-medium text-slate-900">Cluster:</span> {instance.clusterId || "N/A"}
          </p>
          <p className="text-sm text-slate-700">
            <span className="font-medium text-slate-900">Repository:</span> {instance.repository || "N/A"}
          </p>
        </div>

        {/* Tag */}
        <FormField
          label="Version Tag"
          required
          help="Leave unchanged to keep current version"
        >
          <Input
            type="text"
            value={tag}
            onChange={(e) => setTag(e.target.value)}
            placeholder="e.g., v1.0.0"
            required
          />
        </FormField>

        {/* Description */}
        <FormField label="Description">
          <Input
            type="text"
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            placeholder="Modification description"
          />
        </FormField>

        {/* Current Values — directly editable as YAML */}
        <div className="space-y-2">
          <label className="block text-sm font-medium text-slate-700">
            Configuration Values
          </label>
          <p className="text-xs text-slate-500">
            Editing current deployed values. The full YAML is submitted so nested chart values stay intact.
          </p>
          {modifiedKeys.length > 0 && (
            <div className="flex flex-wrap items-center gap-1.5 text-xs">
              <span className="text-slate-500">Modified:</span>
              {modifiedKeys.map((k) => (
                <span key={k} className="px-1.5 py-0.5 rounded bg-amber-100 text-amber-700 font-mono font-medium">
                  {k}
                </span>
              ))}
            </div>
          )}
          <Textarea
            value={valuesYaml}
            onChange={(e) => setValuesYaml(e.target.value)}
            rows={14}
            placeholder="key: value&#10;nested:&#10;  key: value"
            className="font-mono text-sm"
          />
        </div>

        {/* Values Diff Section */}
        {instance.clusterId && instance.id && (
          <div className="border-t border-slate-200 pt-3">
            <button
              type="button"
              onClick={() => {
                setShowDiff(!showDiff);
              }}
              className="flex items-center gap-2 text-sm font-medium text-indigo-600 hover:text-indigo-700 transition-colors"
            >
              <span>{showDiff ? "Hide" : "Show"} Values Diff</span>
              <span className={`text-xs transition-transform ${showDiff ? "rotate-180" : ""}`}>▼</span>
            </button>

            {showDiff && (
              <div className="mt-3 space-y-3">
                {loadingDiff && (
                  <LoadingState message="Loading values diff..." />
                )}
                {diffError && (
                  <ErrorState title="Diff Error" message={diffError} />
                )}
                {diffData && (
                  <>
                    <div className="grid grid-cols-2 gap-3">
                      {/* Current Values */}
                      <div>
                        <div className="flex items-center gap-2 mb-1">
                          <span className="text-xs font-semibold uppercase tracking-wider text-slate-500">
                            Current
                          </span>
                          <Badge variant="default" size="sm">deployed</Badge>
                        </div>
                        <pre className="text-xs font-mono bg-slate-50 border border-slate-200 rounded-lg p-3 max-h-64 overflow-auto whitespace-pre text-slate-700">
                          {renderDiffValues(diffData.current, diffData.defaults)}
                        </pre>
                      </div>
                      {/* Default Values */}
                      <div>
                        <div className="flex items-center gap-2 mb-1">
                          <span className="text-xs font-semibold uppercase tracking-wider text-slate-500">
                            Defaults
                          </span>
                          <Badge variant="info" size="sm">chart</Badge>
                        </div>
                        <pre className="text-xs font-mono bg-slate-50 border border-slate-200 rounded-lg p-3 max-h-64 overflow-auto whitespace-pre text-slate-500">
                          {renderDiffValues(diffData.defaults, diffData.current)}
                        </pre>
                      </div>
                    </div>
                    {/* Legend */}
                    <p className="text-xs text-slate-500">
                      <strong className="text-amber-600 dark:text-amber-400">Bold amber keys</strong> differ between current and default values.
                    </p>
                    {/* Use Defaults Button */}
                    <button
                      type="button"
                      onClick={applyDefaults}
                      className="inline-flex items-center gap-1.5 text-xs font-medium text-indigo-600 hover:text-indigo-700 bg-indigo-50 hover:bg-indigo-100 border border-indigo-200 rounded-lg px-3 py-1.5 transition-all"
                      title="Replace current values with chart defaults"
                    >
                      <Settings className="w-3.5 h-3.5" />
                      Use Defaults
                    </button>
                  </>
                )}
              </div>
            )}
          </div>
        )}

        <p className="text-xs text-slate-500">
          Update applies the selected chart version and values override. Resource readiness is tracked from the instance list after submit.
        </p>
      </form>
    </Modal>
  );
};

const parseValuesYaml = (source: string): Record<string, any> => {
  const parsed = parseYaml(source);
  if (parsed == null) {
    return {};
  }
  if (typeof parsed !== "object" || Array.isArray(parsed)) {
    throw new Error("Values YAML must be an object");
  }
  return parsed as Record<string, any>;
};
