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

const repositoryKeys = [
  'RESTIC_REPOSITORY',
  'AWS_ACCESS_KEY_ID',
  'AWS_SECRET_ACCESS_KEY',
  'RESTIC_PASSWORD',
  'RESTIC_KEEP_HOURLY',
  'RESTIC_KEEP_DAILY',
  'RESTIC_KEEP_WEEKLY',
  'RESTIC_KEEP_MONTHLY',
];

export function Repositories({ nodes, onChanged }) {
  const [settingsByNode, setSettingsByNode] = useState({});
  const [selectedNodeId, setSelectedNodeId] = useState('');
  const [values, setValues] = useState({});
  const [visibleSecrets, setVisibleSecrets] = useState({});
  const [message, setMessage] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const [saving, setSaving] = useState(false);

  const rows = useMemo(() => nodes.map((node) => {
    const settings = settingsByNode[node.id];
    const repository = settings?.values.RESTIC_REPOSITORY || '';
    return {
      ...node,
      backend: backendName(repository),
      repository,
      retention: retentionLabel(settings?.values || {}),
      settingsError: settings?.error,
    };
  }), [nodes, settingsByNode]);

  const selectedSettings = settingsByNode[selectedNodeId];
  const editableFields = (selectedSettings?.fields || []).filter((field) => repositoryKeys.includes(field.key));
  const nodeSignature = nodes.map((node) => node.id).join('|');

  useEffect(() => {
    loadRepositorySettings();
  }, [nodeSignature]);

  useEffect(() => {
    if (!selectedNodeId && rows[0]?.id) setSelectedNodeId(rows[0].id);
  }, [rows, selectedNodeId]);

  useEffect(() => {
    if (selectedSettings?.values) setValues(selectedSettings.values);
  }, [selectedSettings]);

  async function loadRepositorySettings() {
    if (!nodes.length) return;
    setLoading(true);
    setError('');
    const results = await Promise.allSettled(nodes.map(async (node) => {
      const result = await api.get(`/settings/${encodeURIComponent(node.id)}`);
      return {
        nodeId: node.id,
        fields: result.data.fields || [],
        values: Object.fromEntries((result.data.fields || []).map((field) => [field.key, field.value || ''])),
      };
    }));

    const next = {};
    results.forEach((result, index) => {
      const node = nodes[index];
      if (result.status === 'fulfilled') {
        next[node.id] = result.value;
      } else {
        next[node.id] = { fields: [], values: {}, error: errorMessage(result.reason) };
      }
    });
    setSettingsByNode(next);
    setLoading(false);
  }

  async function saveRepository(event) {
    event.preventDefault();
    if (!selectedNodeId) return;
    setSaving(true);
    setMessage('');
    setError('');
    try {
      const result = await api.put(`/settings/${encodeURIComponent(selectedNodeId)}`, { values });
      const fields = result.data.fields || [];
      const nextValues = Object.fromEntries(fields.map((field) => [field.key, field.value || '']));
      setSettingsByNode((current) => ({
        ...current,
        [selectedNodeId]: { fields, values: nextValues },
      }));
      setValues(nextValues);
      setMessage('Repository settings saved.');
      await onChanged?.();
    } catch (requestError) {
      setError(errorMessage(requestError));
    } finally {
      setSaving(false);
    }
  }

  return (
    <section className="space-y-5">
      {error ? <Notice tone="bad" text={error} /> : null}
      {message ? <Notice tone="good" text={message} /> : null}

      <div className="overflow-hidden border border-zinc-700 bg-zinc-950/80">
        <div className="flex flex-wrap items-center justify-between gap-3 border-b border-zinc-800 p-4">
          <div className="flex items-center gap-3">
            <input
              className="h-10 w-64 max-w-full border border-zinc-700 bg-zinc-900 px-3 text-sm text-zinc-100 outline-none"
              disabled
              placeholder="Search..."
              type="text"
            />
            <select className="h-10 border border-zinc-700 bg-zinc-900 px-3 text-sm text-zinc-300 outline-none" disabled>
              <option>All status</option>
            </select>
            <select className="h-10 border border-zinc-700 bg-zinc-900 px-3 text-sm text-zinc-300 outline-none" disabled>
              <option>All backends</option>
            </select>
          </div>
          <button
            className="inline-flex h-10 items-center gap-2 rounded-md border border-zinc-700 px-3 text-sm font-semibold text-zinc-100 hover:border-zinc-500"
            onClick={loadRepositorySettings}
            type="button"
          >
            <Database className="h-4 w-4" />
            Reload
          </button>
        </div>

        <div className="overflow-x-auto">
          <table className="w-full min-w-[880px] text-left text-sm">
            <thead className="border-b border-zinc-800 text-xs uppercase tracking-wide text-zinc-400">
              <tr>
                <th className="px-4 py-3 font-semibold">Name</th>
                <th className="px-4 py-3 font-semibold">Backend</th>
                <th className="px-4 py-3 font-semibold">Repository</th>
                <th className="px-4 py-3 font-semibold">Retention</th>
                <th className="px-4 py-3 font-semibold">Status</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-zinc-800">
              {rows.map((row) => (
                <tr
                  className={`cursor-pointer hover:bg-zinc-900 ${selectedNodeId === row.id ? 'bg-red-950/20' : ''}`}
                  key={row.id}
                  onClick={() => setSelectedNodeId(row.id)}
                >
                  <td className="px-4 py-4 font-semibold text-red-400">{row.name}</td>
                  <td className="px-4 py-4 text-zinc-300">
                    <span className="inline-flex items-center gap-2">
                      <Cloud className="h-4 w-4 text-zinc-500" />
                      {row.backend}
                    </span>
                  </td>
                  <td className="max-w-[30rem] truncate px-4 py-4 font-mono text-xs text-zinc-300">{row.repository || '-'}</td>
                  <td className="px-4 py-4 text-zinc-300">{row.retention}</td>
                  <td className="px-4 py-4">
                    <span className={`inline-flex h-3 w-3 rounded-full ${statusClass(row, loading)}`} title={row.settingsError || row.lastHealthStatus || 'unknown'} />
                  </td>
                </tr>
              ))}
              {!rows.length ? (
                <tr>
                  <td className="px-4 py-10 text-center text-zinc-500" colSpan="5">No nodes configured.</td>
                </tr>
              ) : null}
            </tbody>
          </table>
        </div>
        <div className="border-t border-zinc-800 px-4 py-3 text-right text-sm text-zinc-400">
          <span className="font-semibold text-red-400">{rows.length}</span> repositories
        </div>
      </div>

      {selectedNodeId ? (
        <form className="border border-zinc-700 bg-zinc-950/80" onSubmit={saveRepository}>
          <div className="flex items-center justify-between border-b border-zinc-800 px-4 py-3">
            <div>
              <h2 className="font-semibold text-zinc-100">Repository Settings</h2>
              <p className="text-sm text-zinc-500">{nodes.find((node) => node.id === selectedNodeId)?.name || selectedNodeId}</p>
            </div>
            <button
              className="inline-flex h-9 items-center gap-2 rounded-md border border-red-900 bg-red-950/40 px-3 text-sm text-red-100 hover:border-red-700"
              disabled={saving || Boolean(selectedSettings?.error)}
              type="submit"
            >
              <Save className="h-4 w-4" />
              Save
            </button>
          </div>

          {selectedSettings?.error ? (
            <div className="px-4 py-6 text-sm text-red-300">{selectedSettings.error}</div>
          ) : (
            <div className="grid gap-4 p-4 lg:grid-cols-2">
              {editableFields.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}</span>
                      <span className="font-mono text-xs text-zinc-500">{field.key}</span>
                    </span>
                    <span className="mt-2 flex border border-zinc-700 bg-zinc-900 focus-within:border-red-700">
                      <input
                        className="h-10 min-w-0 flex-1 bg-transparent px-3 text-zinc-100 outline-none"
                        min={field.key.startsWith('RESTIC_KEEP_') ? '0' : undefined}
                        onChange={(event) => setValues((current) => ({ ...current, [field.key]: event.target.value }))}
                        type={field.secret && !secretVisible ? 'password' : field.key.startsWith('RESTIC_KEEP_') ? 'number' : 'text'}
                        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>
          )}
        </form>
      ) : null}
    </section>
  );
}

function backendName(repository) {
  if (!repository) return '-';
  if (repository.startsWith('s3:')) return 's3';
  if (repository.startsWith('sftp:')) return 'sftp';
  if (repository.startsWith('rest:')) return 'rest';
  return 'local';
}

function retentionLabel(values) {
  const parts = [
    ['h', values.RESTIC_KEEP_HOURLY],
    ['d', values.RESTIC_KEEP_DAILY],
    ['w', values.RESTIC_KEEP_WEEKLY],
    ['m', values.RESTIC_KEEP_MONTHLY],
  ].filter(([, value]) => value !== undefined && value !== '');
  if (!parts.length) return '-';
  return parts.map(([label, value]) => `${value}${label}`).join(' ');
}

function statusClass(row, loading) {
  if (loading) return 'bg-amber-400';
  if (row.settingsError) return 'bg-red-500';
  if (row.lastHealthStatus === 'ok' || row.lastHealthStatus === 'healthy') return 'bg-emerald-400 shadow-[0_0_12px_rgba(52,211,153,0.8)]';
  return 'bg-zinc-600';
}

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',
  };
  return <div className={`rounded-md border px-4 py-3 text-sm ${classes[tone]}`}>{text}</div>;
}
