import { Eye, EyeOff, Save } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { api, errorMessage } from '../api.js';

export function Settings({ nodes, onChanged }) {
  const [fields, setFields] = useState([]);
  const [values, setValues] = useState({});
  const [nodeId, setNodeId] = useState(nodes[0]?.id || '');
  const [visibleSecrets, setVisibleSecrets] = useState({});
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState('');
  const [error, setError] = useState('');

  const requiredMissing = useMemo(
    () => fields.filter((field) => field.required && !String(values[field.key] || '').trim()),
    [fields, values],
  );

  async function loadSettings() {
    if (!nodeId) return;
    setError('');
    try {
      const result = await api.get(`/settings/${encodeURIComponent(nodeId)}`);
      setFields(result.data.fields || []);
      setValues(Object.fromEntries((result.data.fields || []).map((field) => [field.key, field.value || ''])));
    } catch (requestError) {
      setError(errorMessage(requestError));
    }
  }

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

  useEffect(() => {
    if (!nodeId && nodes[0]?.id) setNodeId(nodes[0].id);
  }, [nodeId, nodes]);

  async function saveSettings(event) {
    event.preventDefault();
    setSaving(true);
    setMessage('');
    setError('');
    try {
      const result = await api.put(`/settings/${encodeURIComponent(nodeId)}`, { values });
      setFields(result.data.fields || []);
      setValues(Object.fromEntries((result.data.fields || []).map((field) => [field.key, field.value || ''])));
      setMessage('Settings saved. Running jobs use the updated values; a changed PORT still needs a backend restart.');
      await onChanged?.();
    } catch (requestError) {
      setError(errorMessage(requestError));
    } finally {
      setSaving(false);
    }
  }

  return (
    <section className="space-y-5">
      <div className="border-b border-zinc-800 pb-5">
        <h1 className="text-2xl font-semibold text-zinc-100">Settings</h1>
        <p className="mt-2 max-w-3xl text-sm leading-6 text-zinc-500">
          Values are written to the selected node agent. Keep access to this UI restricted because secrets are editable here.
        </p>
      </div>

      {error ? <Notice tone="bad" text={error} /> : null}
      {message ? <Notice tone="good" text={message} /> : null}
      {requiredMissing.length ? (
        <Notice tone="warn" text={`Missing required values: ${requiredMissing.map((field) => field.key).join(', ')}`} />
      ) : null}

      <form className="rounded-md border border-zinc-800 bg-zinc-900/70" onSubmit={saveSettings}>
        <div className="border-b border-zinc-800 p-4">
          <label className="block max-w-sm text-sm text-zinc-300">
            Node
            <select
              className="mt-2 h-10 w-full rounded-md border border-zinc-700 bg-zinc-950 px-3 text-zinc-100 outline-none"
              onChange={(event) => setNodeId(event.target.value)}
              value={nodeId}
            >
              <option value="">Select node</option>
              {nodes.map((node) => <option key={node.id} value={node.id}>{node.name}</option>)}
            </select>
          </label>
        </div>
        <div className="grid gap-4 p-4 lg:grid-cols-2">
          {fields.map((field) => {
            const secretVisible = visibleSecrets[field.key];
            return (
              <label className="block text-sm text-zinc-300" key={field.key}>
                <span className="flex items-center justify-between gap-3">
                  <span>
                    {field.label}
                    {field.required ? <span className="text-red-300"> *</span> : null}
                  </span>
                  <span className="font-mono text-xs text-zinc-500">{field.key}</span>
                </span>
                <span className="mt-2 flex rounded-md border border-zinc-700 bg-zinc-950 focus-within:border-cyan-600">
                  <input
                    className="h-10 min-w-0 flex-1 bg-transparent px-3 text-zinc-100 outline-none"
                    onChange={(event) => setValues((current) => ({ ...current, [field.key]: event.target.value }))}
                    min={field.key.startsWith('RESTIC_KEEP_') ? '0' : undefined}
                    type={inputType(field, secretVisible)}
                    value={values[field.key] || ''}
                  />
                  {field.secret ? (
                    <button
                      className="flex h-10 w-10 items-center justify-center border-l border-zinc-800 text-zinc-400 hover:text-zinc-100"
                      onClick={() => setVisibleSecrets((current) => ({ ...current, [field.key]: !current[field.key] }))}
                      type="button"
                    >
                      {secretVisible ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
                    </button>
                  ) : null}
                </span>
              </label>
            );
          })}
        </div>
        <div className="flex justify-end border-t border-zinc-800 px-4 py-3">
          <button
            className="inline-flex h-9 items-center gap-2 rounded-md border border-cyan-800 bg-cyan-950 px-3 text-sm text-cyan-100 hover:bg-cyan-900"
            disabled={saving || !nodeId}
            type="submit"
          >
            <Save className="h-4 w-4" />
            Save Settings
          </button>
        </div>
      </form>
    </section>
  );
}

function inputType(field, secretVisible) {
  if (field.secret && !secretVisible) return 'password';
  if (field.key.startsWith('RESTIC_KEEP_')) return 'number';
  return 'text';
}

function Notice({ text, tone }) {
  const classes = {
    bad: 'border-red-900 bg-red-950/50 text-red-200',
    good: 'border-emerald-900 bg-emerald-950/50 text-emerald-200',
    warn: 'border-amber-900 bg-amber-950/50 text-amber-200',
  };

  return <div className={`rounded-md border px-4 py-3 text-sm ${classes[tone]}`}>{text}</div>;
}
