(function () {
  'use strict';

  /* ── Daten aus DOM (CSP-sicher via <script type="application/json">) ──── */
  const ALL_DOCTORS = JSON.parse(
    document.getElementById('calDoctorsData').textContent
  );
  const BASE = '/calendar/api';

  /* ── State ──────────────────────────────────────────────────────────────── */
  let currentDate = new Date();
  let appointments = [];
  let holidays     = {};
  let visibleDocs  = new Set(ALL_DOCTORS.map(d => d.id));
  let editingId    = null;

  /* ── Hilfsfunktionen ────────────────────────────────────────────────────── */
  const pad     = n => String(n).padStart(2, '0');
  const toISO   = d => `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
  const addDays = (d, n) => { const r = new Date(d); r.setDate(r.getDate() + n); return r; };

  const WDAYS  = ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'];
  const MONTHS = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];

  const TIME_SLOTS = (() => {
    const s = [];
    for (let h = 0; h < 24; h++)
      for (let m = 0; m < 60; m += 15)
        s.push(`${pad(h)}:${pad(m)}`);
    return s;
  })();

  async function apiFetch(path, opts = {}) {
    const res = await fetch(BASE + path, {
      headers: { 'Content-Type': 'application/json' },
      ...opts,
      body: opts.body ? JSON.stringify(opts.body) : undefined,
    });
    const data = await res.json();
    if (!res.ok) throw new Error(data.error || 'API-Fehler');
    return data;
  }

  function showToast(msg, isError = false) {
    const el  = document.getElementById('calToast');
    const txt = document.getElementById('calToastMsg');
    txt.textContent = msg;
    el.className = `toast align-items-center border-0 ${isError ? 'text-bg-danger' : 'text-bg-dark'}`;
    bootstrap.Toast.getOrCreateInstance(el, { delay: 2800 }).show();
  }

  /* ── Tages-Daten laden ──────────────────────────────────────────────────── */
  async function loadDay() {
    const iso = toISO(currentDate);
    appointments = await apiFetch(`/appointments/${iso}`);
    await ensureHolidays(currentDate.getFullYear());
    renderToolbar();
    renderHolidayBanner();
    renderColumns();
    renderMiniCal();
  }

  async function ensureHolidays(year) {
    if (holidays[year] !== undefined) return;
    try {
      const data = await apiFetch(`/holidays/${year}`);
      holidays[year] = {};
      for (const h of data.holidays) {
        if (!holidays[year][h.date]) holidays[year][h.date] = [];
        holidays[year][h.date].push(h);
      }
    } catch { holidays[year] = {}; }
  }

  /* ── Toolbar ────────────────────────────────────────────────────────────── */
  function renderToolbar() {
    const wd  = WDAYS[currentDate.getDay()];
    const day = currentDate.getDate();
    const mon = MONTHS[currentDate.getMonth()];
    const yr  = currentDate.getFullYear();
    document.getElementById('btnDateDisplay').textContent =
      `${wd}, ${day}. ${mon} ${yr}`;
  }

  /* ── Feiertagsbanner ────────────────────────────────────────────────────── */
  function renderHolidayBanner() {
    const iso  = toISO(currentDate);
    const list = holidays[currentDate.getFullYear()]?.[iso];
    const el   = document.getElementById('calHolidayBanner');
    if (list?.length) {
      document.getElementById('calHolidayText').textContent =
        'Feiertag: ' + list.map(h => h.name).join(' · ');
      el.style.display = 'flex';
    } else {
      el.style.display = 'none';
    }
  }

  /* ── Zeitachse ──────────────────────────────────────────────────────────── */
  function buildTimeAxis() {
    const ax = document.getElementById('calTimeAxis');
    ax.innerHTML = TIME_SLOTS.map(t => {
      const h = t.endsWith(':00');
      return `<div class="cal-time-label ${h ? 'hour' : ''}">${h ? t : ''}</div>`;
    }).join('');
  }

  /* ── Spalten rendern ────────────────────────────────────────────────────── */
  function renderColumns() {
    const visible = ALL_DOCTORS.filter(d => visibleDocs.has(d.id));
    const headers = document.getElementById('calColHeadersInner');
    const cols    = document.getElementById('calColumnsInner');
    const iso     = toISO(currentDate);
    const isWEnd  = [0, 6].includes(currentDate.getDay());

    const countMap = {};
    for (const a of appointments)
      countMap[a.doctor_id] = (countMap[a.doctor_id] || 0) + 1;

    if (!visible.length) {
      headers.innerHTML = '';
      cols.innerHTML = `
        <div class="d-flex flex-column align-items-center justify-content-center w-100 text-muted py-5">
          <i class="bi bi-person-x fs-1 mb-2"></i>
          <div>Keine Ärzte ausgewählt</div>
        </div>`;
      return;
    }

    headers.innerHTML = visible.map(d => `
      <div class="col-header">
        <span class="doc-dot" style="background:${d.color}"></span>
        <div>
          <div class="col-header-name">${esc(d.name)}</div>
        </div>
        <span class="col-header-count">${countMap[d.id] || 0}</span>
        <input type="color" class="col-header-color ms-1" value="${d.color}"
               title="Farbe ändern" data-doc="${d.id}">
      </div>
    `).join('');

    cols.innerHTML = visible.map(d => `
      <div class="doc-col" id="docCol-${d.id}" data-doc="${d.id}">
        ${TIME_SLOTS.map(t => `
          <div class="slot-row ${t.endsWith(':00') ? 'hour-start' : ''} ${isWEnd ? 'weekend' : ''}"
               data-time="${t}" data-doc="${d.id}"></div>
        `).join('')}
      </div>
    `).join('');

    /* Termin-Blöcke */
    const byDoc = {};
    for (const a of appointments) {
      if (!byDoc[a.doctor_id]) byDoc[a.doctor_id] = [];
      byDoc[a.doctor_id].push(a);
    }
    for (const d of visible) {
      const col = document.getElementById(`docCol-${d.id}`);
      if (col) (byDoc[d.id] || []).forEach(a => renderApptBlock(col, a, d.color));
    }

    updateNowLine();

    /* Slot-Klick */
    cols.querySelectorAll('.slot-row').forEach(slot =>
      slot.addEventListener('click', () =>
        openApptModal(null, slot.dataset.doc, iso, slot.dataset.time))
    );

    /* Farb-Picker */
    headers.querySelectorAll('.col-header-color').forEach(inp => {
      inp.addEventListener('change', async () => {
        const docId = parseInt(inp.dataset.doc);
        const color = inp.value;
        await apiFetch(`/doctors/${docId}/color`, { method: 'PATCH', body: { color } });
        const doc = ALL_DOCTORS.find(d => d.id === docId);
        if (doc) doc.color = color;
        renderDocList();
        renderColumns();
      });
    });
  }

  function renderApptBlock(col, a, color) {
    const idx   = TIME_SLOTS.indexOf(a.time);
    if (idx < 0) return;
    const slots = Math.max(1, Math.round(a.duration / 15));
    const block = document.createElement('div');
    block.className = `appt-block status-${a.status}`;
    block.style.cssText =
      `top:${idx * 40 + 2}px; height:${slots * 40 - 4}px; background:${color}28; border-color:${color};`;
    block.innerHTML = `
      <div class="appt-patient">${esc(a.patient_name)}</div>
      ${slots > 1 ? `<div class="appt-time">${a.time} · ${a.duration} min</div>` : ''}
    `;
    block.addEventListener('click', e => { e.stopPropagation(); openApptModal(a); });
    col.appendChild(block);
  }

  function updateNowLine() {
    document.querySelectorAll('.now-line').forEach(n => n.remove());
    if (toISO(new Date()) !== toISO(currentDate)) return;
    const mins = new Date().getHours() * 60 + new Date().getMinutes();
    const top  = (mins / 15) * 40;
    document.querySelectorAll('.doc-col').forEach(col => {
      const line       = document.createElement('div');
      line.className   = 'now-line';
      line.style.top   = `${top}px`;
      line.innerHTML   = '<div class="now-dot"></div>';
      col.appendChild(line);
    });
  }
  setInterval(updateNowLine, 30000);

  /* ── Arztliste (Sidebar) ────────────────────────────────────────────────── */
  function renderDocList() {
    const el = document.getElementById('docList');
    el.innerHTML = ALL_DOCTORS.map(d => `
      <div class="doc-item ${visibleDocs.has(d.id) ? 'active' : ''}" data-id="${d.id}">
        <span class="doc-dot" style="background:${d.color}"></span>
        <span style="font-size:13px; flex:1;">${esc(d.name)}</span>
        <span class="doc-check">
          ${visibleDocs.has(d.id)
            ? '<i class="bi bi-check text-white" style="font-size:11px;"></i>'
            : ''}
        </span>
      </div>
    `).join('');

    el.querySelectorAll('.doc-item').forEach(item => {
      item.addEventListener('click', () => {
        const id = parseInt(item.dataset.id);
        visibleDocs.has(id) ? visibleDocs.delete(id) : visibleDocs.add(id);
        renderDocList();
        renderColumns();
      });
    });
  }

  /* ── Mini-Kalender ──────────────────────────────────────────────────────── */
  let miniYear  = new Date().getFullYear();
  let miniMonth = new Date().getMonth();

  async function renderMiniCal(yr, mo) {
    if (yr !== undefined) { miniYear = yr; miniMonth = mo; }
    await ensureHolidays(miniYear);

    const first   = new Date(miniYear, miniMonth, 1);
    const last    = new Date(miniYear, miniMonth + 1, 0);
    const startWd = (first.getDay() + 6) % 7;

    let html = `
      <div class="d-flex align-items-center justify-content-between mb-2">
        <button class="btn btn-sm btn-link p-0 text-muted" id="miniPrev">
          <i class="bi bi-chevron-left"></i>
        </button>
        <small class="fw-semibold">${MONTHS[miniMonth].substring(0,3)} ${miniYear}</small>
        <button class="btn btn-sm btn-link p-0 text-muted" id="miniNext">
          <i class="bi bi-chevron-right"></i>
        </button>
      </div>
      <div class="mini-cal-grid">
        ${['Mo','Di','Mi','Do','Fr','Sa','So'].map(w => `<div class="mini-wd">${w}</div>`).join('')}
    `;

    for (let i = 0; i < startWd; i++) html += '<div></div>';

    for (let day = 1; day <= last.getDate(); day++) {
      const d2  = new Date(miniYear, miniMonth, day);
      const iso = toISO(d2);
      const tod = toISO(new Date()) === iso;
      const sel = toISO(currentDate) === iso;
      const hol = !!(holidays[miniYear]?.[iso]);
      html += `<div class="mini-day ${tod?'today':''} ${sel?'selected':''} ${hol?'holiday':''}"
                    data-iso="${iso}">${day}</div>`;
    }
    html += '</div>';

    const mc = document.getElementById('miniCal');
    mc.innerHTML = html;

    mc.querySelector('#miniPrev').addEventListener('click', () => {
      let m = miniMonth - 1, y = miniYear;
      if (m < 0) { m = 11; y--; }
      renderMiniCal(y, m);
    });
    mc.querySelector('#miniNext').addEventListener('click', () => {
      let m = miniMonth + 1, y = miniYear;
      if (m > 11) { m = 0; y++; }
      renderMiniCal(y, m);
    });
    mc.querySelectorAll('.mini-day[data-iso]').forEach(el => {
      el.addEventListener('click', () => {
        const [y, m, d] = el.dataset.iso.split('-').map(Number);
        currentDate = new Date(y, m - 1, d);
        loadDay();
      });
    });
  }

  /* ── Patienten-Autocomplete ─────────────────────────────────────────────── */
  let acTimer = null;

  function initPatientAutocomplete() {
    const input    = document.getElementById('fPatient');
    const dropdown = document.getElementById('patientDropdown');
    const hiddenId = document.getElementById('fPatientId');

    function hideDropdown() {
      dropdown.style.display = 'none';
      dropdown.innerHTML = '';
    }

    function selectPatient(p) {
      input.value    = `${p.firstname} ${p.lastname}`;
      hiddenId.value = p.id;
      hideDropdown();
    }

    input.addEventListener('input', () => {
      clearTimeout(acTimer);
      hiddenId.value = ''; // Freitext → ID zurücksetzen
      const q = input.value.trim();

      if (q.length < 1) { hideDropdown(); return; }

      acTimer = setTimeout(async () => {
        try {
          const results = await apiFetch(
            `/patients/search?q=${encodeURIComponent(q)}`
          );

          if (!results.length) { hideDropdown(); return; }

          dropdown.innerHTML = results.map(p => {
            const bd = p.birthdate
              ? new Date(p.birthdate).toLocaleDateString('de-DE')
              : '';
            return `
              <div class="ac-item d-flex align-items-center gap-2 px-3 py-2"
                   style="cursor:pointer; font-size:13px; border-bottom:1px solid #f0f0f0;"
                   data-id="${p.id}"
                   data-name="${esc(p.firstname)} ${esc(p.lastname)}">
                <i class="bi bi-person text-muted"></i>
                <div>
                  <div class="fw-semibold">${esc(p.firstname)} ${esc(p.lastname)}</div>
                  ${bd ? `<div class="text-muted" style="font-size:11px;">*${bd}</div>` : ''}
                </div>
              </div>`;
          }).join('');

          dropdown.style.display = 'block';

          dropdown.querySelectorAll('.ac-item').forEach(item => {
            // Hover-Effekt
            item.addEventListener('mouseenter', () =>
              item.style.background = '#f0f5ff'
            );
            item.addEventListener('mouseleave', () =>
              item.style.background = ''
            );
            // Auswahl
            item.addEventListener('mousedown', e => {
              e.preventDefault(); // verhindert blur vor click
              selectPatient({
                id:        parseInt(item.dataset.id),
                firstname: item.dataset.name.split(' ')[0],
                lastname:  item.dataset.name.split(' ').slice(1).join(' '),
              });
            });
          });
        } catch { hideDropdown(); }
      }, 220);
    });

    // Dropdown schließen wenn Fokus woanders hin geht
    input.addEventListener('blur', () => {
      setTimeout(hideDropdown, 200);
    });

    // Modal schließt → Dropdown aufräumen
    document.getElementById('apptModal').addEventListener('hidden.bs.modal', hideDropdown);
  }

  /* ── Termin-Modal ───────────────────────────────────────────────────────── */
  function populateTimeSelect() {
    const sel = document.getElementById('fTime');
    sel.innerHTML = TIME_SLOTS.map(t =>
      `<option value="${t}">${t}</option>`
    ).join('');
  }

  function populateDoctorSelect() {
    const sel = document.getElementById('fDoctor');
    sel.innerHTML = ALL_DOCTORS.map(d =>
      `<option value="${d.id}">${esc(d.name)}</option>`
    ).join('');
  }

  function openApptModal(appt, docId, date, time) {
    editingId = appt?.id ?? null;
    document.getElementById('apptModalTitle').textContent =
      appt ? 'Termin bearbeiten' : 'Neuer Termin';
    document.getElementById('btnApptDelete').style.display = appt ? '' : 'none';

    populateTimeSelect();
    populateDoctorSelect();

    document.getElementById('fDate').value     = appt?.date         ?? (date || toISO(currentDate));
    document.getElementById('fTime').value     = appt?.time         ?? (time || '08:00');
    document.getElementById('fDoctor').value   = appt?.doctor_id    ?? (docId || ALL_DOCTORS[0]?.id || '');
    document.getElementById('fPatient').value  = appt?.patient_name ?? '';
    document.getElementById('fPatientId').value = '';   // ← immer zurücksetzen
    document.getElementById('fDuration').value = appt?.duration     ?? 15;
    document.getElementById('fStatus').value   = appt?.status       ?? 'scheduled';
    document.getElementById('fNotes').value    = appt?.notes        ?? '';

    bootstrap.Modal.getOrCreateInstance(
      document.getElementById('apptModal')
    ).show();
    setTimeout(() => document.getElementById('fPatient').focus(), 300);
  }

  async function saveAppt() {
    const payload = {
      doctor_id:    parseInt(document.getElementById('fDoctor').value),
      date:         document.getElementById('fDate').value,
      time:         document.getElementById('fTime').value,
      duration:     parseInt(document.getElementById('fDuration').value),
      patient_name: document.getElementById('fPatient').value.trim(),
      notes:        document.getElementById('fNotes').value.trim(),
      status:       document.getElementById('fStatus').value,
    };
    if (!payload.patient_name) { showToast('Patientenname fehlt', true); return; }

    try {
      if (editingId) {
        await apiFetch(`/appointments/${editingId}`, { method: 'PUT', body: payload });
        showToast('Termin gespeichert');
      } else {
        await apiFetch('/appointments', { method: 'POST', body: payload });
        showToast('Termin erstellt');
      }
      bootstrap.Modal.getInstance(document.getElementById('apptModal')).hide();
      await loadDay();
    } catch (e) { showToast(e.message, true); }
  }

  async function deleteAppt() {
    if (!confirm('Termin wirklich löschen?')) return;
    try {
      await apiFetch(`/appointments/${editingId}`, { method: 'DELETE' });
      showToast('Termin gelöscht');
      bootstrap.Modal.getInstance(document.getElementById('apptModal')).hide();
      await loadDay();
    } catch (e) { showToast(e.message, true); }
  }

  /* ── Events ─────────────────────────────────────────────────────────────── */
  function setupEvents() {
    document.getElementById('btnPrev').addEventListener('click', () => {
      currentDate = addDays(currentDate, -1); loadDay();
    });
    document.getElementById('btnNext').addEventListener('click', () => {
      currentDate = addDays(currentDate,  1); loadDay();
    });
    document.getElementById('btnToday').addEventListener('click', () => {
      currentDate = new Date(); loadDay();
    });
    document.getElementById('btnNewAppt').addEventListener('click', () =>
      openApptModal(null)
    );
    document.getElementById('btnApptSave').addEventListener('click', saveAppt);
    document.getElementById('btnApptDelete').addEventListener('click', deleteAppt);

    document.addEventListener('keydown', e => {
      if (document.querySelector('.modal.show')) return;
      if (e.key === 'ArrowLeft')  { currentDate = addDays(currentDate, -1); loadDay(); }
      if (e.key === 'ArrowRight') { currentDate = addDays(currentDate,  1); loadDay(); }
      if (e.key === 't')          { currentDate = new Date(); loadDay(); }
    });
  }

  function esc(s) {
    return String(s || '')
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
  }

  /* ── Start ──────────────────────────────────────────────────────────────── */
  buildTimeAxis();
  renderDocList();
  setupEvents();
  initPatientAutocomplete();
  loadDay()
    .then(() => {
      // Scroll zu 07:00 (Slot 28)
      document.getElementById('calScroll').scrollTop = 28 * 40 - 60;
    })
    .catch(err => {
      console.error(err);
      showToast('Verbindung zum Server fehlgeschlagen', true);
    });

})();
