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

export function Scheduler({ onChanged, schedules, vms }) {
  const [drafts, setDrafts] = useState(() => mergeSchedules(vms, schedules));
  const [dirty, setDirty] = useState(false);
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState('');
  const [error, setError] = useState('');

  const rows = useMemo(() => mergeSchedules(vms, drafts), [drafts, vms]);

  useEffect(() => {
    if (!dirty) {
      setDrafts(mergeSchedules(vms, schedules));
    }
  }, [dirty, schedules, vms]);

  async function saveSchedules(event) {
    event.preventDefault();
    setSaving(true);
    setMessage('');
    setError('');
    try {
      const payload = rows
        .filter((row) => row.enabled)
        .map((row) => ({
          id: row.id,
          nodeId: row.nodeId,
          vmName: row.vmName,
          enabled: row.enabled,
          intervalHours: Number(row.intervalHours) || 24,
          nextRunAt: row.nextRunAt,
          lastRunAt: row.lastRunAt,
          lastError: row.lastError,
          timeOfDay: row.timeOfDay || '02:00',
        }));
      const result = await api.put('/schedules', { schedules: payload });
      setDrafts(mergeSchedules(vms, result.data));
      setDirty(false);
      setMessage('Scheduler saved.');
      await onChanged?.();
    } catch (requestError) {
      setError(errorMessage(requestError));
    } finally {
      setSaving(false);
    }
  }

  function updateRow(nodeId, vmName, values) {
    setDirty(true);
    setDrafts((current) => mergeSchedules(vms, current).map((row) => (
      row.nodeId === nodeId && row.vmName === vmName ? { ...row, ...values } : row
    )));
  }

  return (
    <section className="space-y-5">
      <div className="border-b border-zinc-800 pb-5">
        <h1 className="text-2xl font-semibold text-zinc-100">Scheduler</h1>
        <p className="mt-2 max-w-3xl text-sm leading-6 text-zinc-500">
          Configure automatic backups per VM. Schedules are stored on the backend and run while the backend service is active.
        </p>
      </div>

      {error ? <Notice tone="bad" text={error} /> : null}
      {message ? <Notice tone="good" text={message} /> : null}

      <form className="overflow-hidden rounded-md border border-zinc-800 bg-zinc-900/70" onSubmit={saveSchedules}>
        <div className="overflow-x-auto">
          <table className="w-full min-w-[760px] text-left text-sm">
            <thead className="border-b border-zinc-800 text-xs uppercase text-zinc-500">
              <tr>
                <th className="px-4 py-3 font-medium">Enabled</th>
                <th className="px-4 py-3 font-medium">VM</th>
                <th className="px-4 py-3 font-medium">Node</th>
                <th className="px-4 py-3 font-medium">Interval</th>
                <th className="px-4 py-3 font-medium">Time</th>
                <th className="px-4 py-3 font-medium">Next Run</th>
                <th className="px-4 py-3 font-medium">Last Run</th>
                <th className="px-4 py-3 font-medium">Last Error</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-zinc-800">
              {rows.map((row) => (
                <tr key={`${row.nodeId}:${row.vmName}`}>
                  <td className="px-4 py-3">
                    <input
                      checked={row.enabled}
                      className="h-4 w-4 accent-cyan-500"
                      onChange={(event) => updateRow(row.nodeId, row.vmName, { enabled: event.target.checked })}
                      type="checkbox"
                    />
                  </td>
                  <td className="px-4 py-3 font-medium text-zinc-100">{row.vmName}</td>
                  <td className="px-4 py-3 text-zinc-300">{row.nodeName || '-'}</td>
                  <td className="px-4 py-3">
                    <select
                      className="h-9 rounded-md border border-zinc-700 bg-zinc-950 px-2 text-zinc-100 outline-none"
                      onChange={(event) => updateRow(row.nodeId, row.vmName, { intervalHours: Number(event.target.value), nextRunAt: null })}
                      value={row.intervalHours}
                    >
                      <option value={6}>Every 6 hours</option>
                      <option value={12}>Every 12 hours</option>
                      <option value={24}>Daily</option>
                      <option value={168}>Weekly</option>
                    </select>
                  </td>
                  <td className="px-4 py-3">
                    <input
                      className="h-9 rounded-md border border-zinc-700 bg-zinc-950 px-2 text-zinc-100 outline-none"
                      onChange={(event) => updateRow(row.nodeId, row.vmName, { timeOfDay: event.target.value, nextRunAt: null })}
                      type="time"
                      value={row.timeOfDay || '02:00'}
                    />
                  </td>
                  <td className="px-4 py-3 text-zinc-300">{formatTime(row.nextRunAt)}</td>
                  <td className="px-4 py-3 text-zinc-300">{formatTime(row.lastRunAt)}</td>
                  <td className="px-4 py-3 text-red-300">{row.lastError || '-'}</td>
                </tr>
              ))}
              {!rows.length ? (
                <tr>
                  <td className="px-4 py-8 text-center text-zinc-500" colSpan="8">
                    No VMs loaded.
                  </td>
                </tr>
              ) : null}
            </tbody>
          </table>
        </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}
            type="submit"
          >
            <Save className="h-4 w-4" />
            Save Scheduler
          </button>
        </div>
      </form>
    </section>
  );
}

function mergeSchedules(vms, schedules) {
  const byVm = new Map((schedules || []).map((schedule) => [`${schedule.nodeId}:${schedule.vmName}`, schedule]));
  return (vms || []).map((vm) => ({
    id: byVm.get(`${vm.nodeId}:${vm.name}`)?.id,
    nodeId: vm.nodeId,
    nodeName: vm.nodeName,
    vmName: vm.name,
    enabled: Boolean(byVm.get(`${vm.nodeId}:${vm.name}`)?.enabled),
    intervalHours: byVm.get(`${vm.nodeId}:${vm.name}`)?.intervalHours || 24,
    timeOfDay: byVm.get(`${vm.nodeId}:${vm.name}`)?.timeOfDay || '02:00',
    nextRunAt: byVm.get(`${vm.nodeId}:${vm.name}`)?.nextRunAt || null,
    lastRunAt: byVm.get(`${vm.nodeId}:${vm.name}`)?.lastRunAt || null,
    lastError: byVm.get(`${vm.nodeId}:${vm.name}`)?.lastError || '',
  }));
}

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>;
}

function formatTime(value) {
  if (!value) return '-';
  return new Intl.DateTimeFormat(undefined, { dateStyle: 'short', timeStyle: 'short' }).format(new Date(value));
}
