import { useState, useEffect, useMemo } from 'react';
import { useParams, useNavigate, Link } from 'react-router-dom';
import { ChevronDown, RefreshCw, Save, ArrowLeft, AlertCircle, KeyRound } from 'lucide-react';
import { connectivityAPI } from '../../services/api';
import {
  Toast, useToasts, toastEvent, apiError, typeMeta,
  GROUP_TYPES, TypeIcon,
} from './shared';

const inputCls =
  'w-full rounded-md border border-gray-300 px-3 py-2 text-sm text-gray-800 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500';
const monoCls =
  'w-full rounded-md border border-gray-300 px-3 py-2 font-mono text-xs text-gray-800 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500 resize-y';

function FieldRow({ label, required, hint, children, error }) {
  return (
    <div className="flex flex-col gap-1.5">
      <label className="text-sm font-medium text-gray-700">
        {label}
        {required && <span className="text-red-500" aria-hidden="true"> *</span>}
      </label>
      {children}
      {error && <p className="text-xs text-red-600">{error}</p>}
      {hint && !error && <p className="text-xs text-gray-400">{hint}</p>}
    </div>
  );
}

// A write-only secret control: on a new connection it's a plain editable field;
// on edit it shows "•••• set" with a Replace button that reveals the input.
function SecretField({ label, required, hint, isEdit, hasExisting, value, onChange, multiline, placeholder }) {
  const [replacing, setReplacing] = useState(!isEdit || !hasExisting);
  if (isEdit && hasExisting && !replacing) {
    return (
      <FieldRow label={label} required={required} hint={hint}>
        <div className="flex items-center gap-3">
          <span className="inline-flex items-center gap-1.5 text-sm text-gray-500 bg-gray-50 border border-gray-200 rounded-md px-3 py-2">
            <KeyRound className="h-4 w-4 text-gray-400" />
            •••• set
          </span>
          <button
            type="button"
            onClick={() => { setReplacing(true); }}
            className="text-sm font-medium text-primary-600 hover:text-primary-700"
          >
            Replace
          </button>
        </div>
      </FieldRow>
    );
  }
  return (
    <FieldRow label={label} required={required && !isEdit} hint={hint}>
      {multiline ? (
        <textarea
          value={value}
          onChange={(e) => onChange(e.target.value)}
          rows={6}
          autoComplete="off"
          spellCheck="false"
          placeholder={placeholder}
          className={monoCls}
        />
      ) : (
        <input
          type="password"
          value={value}
          onChange={(e) => onChange(e.target.value)}
          autoComplete="new-password"
          placeholder={placeholder}
          className={inputCls}
        />
      )}
      {isEdit && hasExisting && (
        <button
          type="button"
          onClick={() => { onChange(''); setReplacing(false); }}
          className="text-xs text-gray-500 hover:text-gray-700 self-start"
        >
          Keep existing secret
        </button>
      )}
    </FieldRow>
  );
}

const EMPTY = {
  name: '',
  // sshuttle
  host: '', port: '', user: '', auth: 'key', private_key: '', password: '', known_hosts: '',
  // proxy
  scheme: 'socks5', proxy_user: '', proxy_password: '',
  // wireguard / openvpn
  conf: '',
};

export default function ConnectionForm() {
  const toasts = useToasts();
  const navigate = useNavigate();
  const { group, id } = useParams();
  const isEdit = id && id !== 'new';

  const groupTypes = GROUP_TYPES[group] || [];
  const [type, setType] = useState(groupTypes[0] || 'wireguard_ext');
  const [form, setForm] = useState(EMPTY);
  const [existing, setExisting] = useState(null); // the loaded connection on edit
  const [loading, setLoading] = useState(isEdit);
  const [saving, setSaving] = useState(false);
  const [loadError, setLoadError] = useState(null);

  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));

  useEffect(() => {
    if (!isEdit) return;
    let cancelled = false;
    (async () => {
      try {
        const res = await connectivityAPI.listConnections();
        const conns = res.data?.connections ?? res.data ?? [];
        const conn = (Array.isArray(conns) ? conns : []).find((c) => c.id === id);
        if (cancelled) return;
        if (!conn) { setLoadError('Connection not found'); setLoading(false); return; }
        setExisting(conn);
        setType(conn.type);
        const cfg = conn.config || {};
        setForm({
          ...EMPTY,
          name: conn.name || '',
          host: cfg.host || '',
          port: cfg.port != null ? String(cfg.port) : '',
          user: cfg.user || '',
          auth: cfg.auth || 'key',
          scheme: cfg.scheme || 'socks5',
          proxy_user: cfg.user || '',
        });
        setLoading(false);
      } catch (err) {
        if (!cancelled) { setLoadError(apiError(err, 'Failed to load connection')); setLoading(false); }
      }
    })();
    return () => { cancelled = true; };
  }, [isEdit, id]);

  // Secrets that already exist on the connection (so we can show "•••• set").
  const hasSecret = useMemo(() => {
    const cfg = existing?.config || {};
    return {
      conf: !!existing && (type === 'wireguard_ext' || type === 'openvpn'),
      private_key: !!existing && type === 'sshuttle' && (cfg.auth || 'key') === 'key',
      password: !!existing && ((type === 'sshuttle' && cfg.auth === 'password') || type === 'proxy'),
      known_hosts: !!existing && type === 'sshuttle',
    };
  }, [existing, type]);

  const buildPayload = () => {
    const config = {};
    const secrets = {};
    if (type === 'wireguard_ext' || type === 'openvpn') {
      if (form.conf.trim()) secrets.conf = form.conf;
    } else if (type === 'sshuttle') {
      config.host = form.host.trim();
      config.port = Number(form.port || 22);
      config.user = form.user.trim();
      config.auth = form.auth;
      if (form.known_hosts.trim()) secrets.known_hosts = form.known_hosts.trim();
      if (form.auth === 'key') {
        if (form.private_key.trim()) secrets.private_key = form.private_key;
      } else if (form.password) {
        secrets.password = form.password;
      }
    } else if (type === 'proxy') {
      config.scheme = form.scheme;
      config.host = form.host.trim();
      config.port = Number(form.port);
      config.user = form.proxy_user.trim();
      if (form.proxy_password) secrets.password = form.proxy_password;
    }
    return { config, secrets };
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!form.name.trim()) { toastEvent('Name is required', 'error'); return; }
    setSaving(true);
    const { config, secrets } = buildPayload();
    try {
      if (isEdit) {
        const fields = { name: form.name.trim(), config };
        if (Object.keys(secrets).length) fields.secrets = secrets;
        await connectivityAPI.updateConnection(id, fields);
        toastEvent(`Saved ${form.name.trim()}`);
      } else {
        await connectivityAPI.createConnection(type, form.name.trim(), config, secrets);
        toastEvent(`Created ${form.name.trim()}`);
      }
      navigate(`/connectivity/${group}`);
    } catch (err) {
      toastEvent(apiError(err, 'Failed to save connection'), 'error');
    } finally {
      setSaving(false);
    }
  };

  if (loading) {
    return (
      <div className="bg-white rounded-lg border border-gray-200 p-6 animate-pulse space-y-3">
        <div className="h-5 bg-gray-200 rounded w-1/3" />
        <div className="h-4 bg-gray-100 rounded w-1/2" />
        <div className="h-32 bg-gray-100 rounded" />
      </div>
    );
  }

  if (loadError) {
    return (
      <div className="bg-red-50 rounded-lg border border-red-200 p-4 flex items-start gap-3">
        <AlertCircle className="h-5 w-5 text-red-500 mt-0.5 shrink-0" />
        <div className="flex-1">
          <p className="text-sm font-medium text-red-800">{loadError}</p>
        </div>
        <Link to={`/connectivity/${group}`} className="btn-secondary text-sm shrink-0">Back</Link>
      </div>
    );
  }

  const meta = typeMeta(type);

  return (
    <div className="max-w-2xl">
      <Toast toasts={toasts} />

      <Link
        to={`/connectivity/${group}`}
        className="inline-flex items-center gap-1.5 text-sm text-gray-500 hover:text-gray-700 mb-4"
      >
        <ArrowLeft className="h-4 w-4" /> Back
      </Link>

      <div className="flex items-center gap-3 mb-6">
        <TypeIcon type={type} />
        <h1 className="text-2xl font-bold text-gray-900">
          {isEdit ? `Edit ${meta.short}` : `Add ${meta.short}`}
        </h1>
      </div>

      <form onSubmit={handleSubmit} className="bg-white rounded-lg border border-gray-200 p-6 flex flex-col gap-4">
        {/* Type picker (only when the group has more than one type and we're adding) */}
        {!isEdit && groupTypes.length > 1 && (
          <FieldRow label="Type">
            <div className="relative">
              <select
                value={type}
                onChange={(e) => setType(e.target.value)}
                className={`${inputCls} appearance-none pr-8`}
              >
                {groupTypes.map((t) => (
                  <option key={t} value={t}>{typeMeta(t).label}</option>
                ))}
              </select>
              <ChevronDown className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
            </div>
          </FieldRow>
        )}

        <FieldRow label="Name" required hint="A label to identify this connection in assignments">
          <input
            type="text"
            value={form.name}
            onChange={(e) => set('name', e.target.value)}
            placeholder={`my-${meta.short.toLowerCase()}`}
            className={inputCls}
          />
        </FieldRow>

        {(type === 'wireguard_ext' || type === 'openvpn') && (
          <SecretField
            label={type === 'wireguard_ext' ? 'WireGuard config (.conf)' : 'OpenVPN profile (.ovpn)'}
            required
            isEdit={isEdit}
            hasExisting={hasSecret.conf}
            value={form.conf}
            onChange={(v) => set('conf', v)}
            multiline
            placeholder={type === 'wireguard_ext'
              ? '[Interface]\nPrivateKey = ...\n\n[Peer]\nPublicKey = ...'
              : 'client\ndev tun\nproto udp\nremote ...'}
            hint="Stored encrypted in the vault. Paste the file contents."
          />
        )}

        {type === 'sshuttle' && (
          <>
            <div className="grid grid-cols-3 gap-3">
              <div className="col-span-2">
                <FieldRow label="Host" required>
                  <input type="text" value={form.host} onChange={(e) => set('host', e.target.value)}
                    placeholder="ssh.example.com" className={inputCls} />
                </FieldRow>
              </div>
              <FieldRow label="Port">
                <input type="number" min="1" max="65535" value={form.port}
                  onChange={(e) => set('port', e.target.value)} placeholder="22" className={inputCls} />
              </FieldRow>
            </div>
            <FieldRow label="User" required>
              <input type="text" value={form.user} onChange={(e) => set('user', e.target.value)}
                placeholder="tunnel" className={inputCls} />
            </FieldRow>
            <FieldRow label="Authentication">
              <div className="flex rounded-md border border-gray-200 overflow-hidden w-fit">
                {['key', 'password'].map((a) => (
                  <button
                    key={a} type="button" onClick={() => set('auth', a)}
                    className={`px-3 py-1.5 text-sm font-medium transition-colors ${
                      form.auth === a ? 'bg-primary-600 text-white' : 'bg-white text-gray-600 hover:bg-gray-50'
                    }`}
                  >
                    {a === 'key' ? 'Private key' : 'Password'}
                  </button>
                ))}
              </div>
            </FieldRow>
            {form.auth === 'key' ? (
              <SecretField
                label="Private key" required isEdit={isEdit} hasExisting={hasSecret.private_key}
                value={form.private_key} onChange={(v) => set('private_key', v)} multiline
                placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"
                hint="Stored encrypted in the vault."
              />
            ) : (
              <SecretField
                label="Password" required isEdit={isEdit} hasExisting={hasSecret.password}
                value={form.password} onChange={(v) => set('password', v)}
              />
            )}
            <SecretField
              label="Pinned host key (known_hosts line)" required isEdit={isEdit}
              hasExisting={hasSecret.known_hosts}
              value={form.known_hosts} onChange={(v) => set('known_hosts', v)}
              placeholder="ssh.example.com ssh-ed25519 AAAA..."
              hint="Get it with: ssh-keyscan -t ed25519 ssh.example.com"
            />
          </>
        )}

        {type === 'proxy' && (
          <>
            <div className="grid grid-cols-3 gap-3">
              <FieldRow label="Scheme">
                <div className="relative">
                  <select value={form.scheme} onChange={(e) => set('scheme', e.target.value)}
                    className={`${inputCls} appearance-none pr-8`}>
                    <option value="socks5">SOCKS5</option>
                    <option value="http">HTTP</option>
                  </select>
                  <ChevronDown className="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 h-4 w-4 text-gray-400" />
                </div>
              </FieldRow>
              <FieldRow label="Host" required>
                <input type="text" value={form.host} onChange={(e) => set('host', e.target.value)}
                  placeholder="proxy.example.com" className={inputCls} />
              </FieldRow>
              <FieldRow label="Port" required>
                <input type="number" min="1" max="65535" value={form.port}
                  onChange={(e) => set('port', e.target.value)} placeholder="1080" className={inputCls} />
              </FieldRow>
            </div>
            <FieldRow label="User" hint="Leave blank for an unauthenticated proxy">
              <input type="text" value={form.proxy_user} onChange={(e) => set('proxy_user', e.target.value)}
                autoComplete="off" placeholder="optional" className={inputCls} />
            </FieldRow>
            <SecretField
              label="Password" isEdit={isEdit} hasExisting={hasSecret.password}
              value={form.proxy_password} onChange={(v) => set('proxy_password', v)}
              hint="Required only when a user is set"
            />
          </>
        )}

        {type === 'tor' && (
          <p className="text-sm text-gray-500">
            Tor needs no configuration. Create the connection, then assign peers or services to it.
          </p>
        )}

        <div className="flex justify-end gap-2 pt-2 border-t border-gray-100">
          <Link to={`/connectivity/${group}`} className="btn-secondary text-sm">Cancel</Link>
          <button
            type="submit"
            disabled={saving}
            className="flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 disabled:opacity-50 rounded-md transition-colors"
          >
            {saving ? <RefreshCw className="h-4 w-4 animate-spin" /> : <Save className="h-4 w-4" />}
            {saving ? 'Saving…' : isEdit ? 'Save changes' : 'Create connection'}
          </button>
        </div>
      </form>
    </div>
  );
}
