(function ($) {
  const csrf = $('meta[name="csrf-token"]').attr('content');
  $.ajaxSetup({
    headers: { 'X-CSRF-TOKEN': csrf, 'X-Requested-With': 'XMLHttpRequest' }
  });

  function toast(msg, ok) {
    const el = $('<div class="alert ' + (ok ? 'alert-success' : 'alert-danger') + ' position-fixed shadow" style="right:16px;bottom:16px;z-index:1080;min-width:240px"></div>').text(msg);
    $('body').append(el);
    setTimeout(() => el.fadeOut(300, () => el.remove()), 2800);
  }
  window.crmToast = toast;

  window.crmPost = function (url, data) {
    data = data || {};
    if (typeof data === 'string') {
      if (data.indexOf('_csrf=') === -1) {
        data += (data ? '&' : '') + '_csrf=' + encodeURIComponent(csrf);
      }
    } else {
      data._csrf = csrf;
    }
    return $.ajax({ url: url, method: 'POST', data: data, dataType: 'json' });
  };

  function centerSidebarActive() {
    var nav = document.querySelector('.sidebar nav');
    var active = nav && nav.querySelector('.nav-link.active');
    if (!nav || !active) {
      return;
    }
    var navBox = nav.getBoundingClientRect();
    var itemBox = active.getBoundingClientRect();
    var delta = (itemBox.top + itemBox.height / 2) - (navBox.top + navBox.height / 2);
    nav.scrollTop += delta;
  }

  centerSidebarActive();
  $(window).on('load', centerSidebarActive);

  function keepPageScroll() {
    try {
      sessionStorage.setItem('aoswareKeepScroll', String(window.scrollY || window.pageYOffset || 0));
    } catch (err) {}
  }
  $(document).on('submit', 'form.task-filters, form.task-search', keepPageScroll);
  $(document).on('click', '.opp-toggle a', keepPageScroll);

  $('[data-sidebar-toggle]').on('click', function () {
    $('.sidebar').toggleClass('open');
    if ($('.sidebar').hasClass('open')) {
      requestAnimationFrame(centerSidebarActive);
    }
  });

  function syncRelatedPick(selectId, boxClass) {
    var type = String($(selectId).val() || '');
    $(boxClass).addClass('d-none').find('select').prop({ disabled: true, required: false });
    if (type) {
      $(boxClass + '[data-type="' + type + '"]').removeClass('d-none').find('select').prop({ disabled: false, required: true });
    }
  }
  function syncTaskRelated() { syncRelatedPick('#qa-task-related-type', '.js-task-related'); }
  function syncNoteRelated() { syncRelatedPick('#qa-note-related-type', '.js-note-related'); }
  function syncCallRelated() { syncRelatedPick('#qa-call-related-type', '.js-call-related'); }
  $(document).on('change', '#qa-task-related-type', syncTaskRelated);
  $(document).on('change', '#qa-note-related-type', syncNoteRelated);
  $(document).on('change', '#qa-call-related-type', syncCallRelated);
  syncTaskRelated();
  syncNoteRelated();
  syncCallRelated();

  let searchTimer;
  $('#globalSearch').on('input', function () {
    const q = $(this).val();
    clearTimeout(searchTimer);
    if (q.length < 2) {
      $('#searchResults').removeClass('open').empty();
      return;
    }
    searchTimer = setTimeout(function () {
      $.getJSON(window.APP_URL + '/search', { q: q }).done(function (res) {
        const box = $('#searchResults').empty().addClass('open');
        if (!res.groups || !res.groups.length) {
          box.append('<div class="p-2 text-muted">No matches</div>');
          return;
        }
        res.groups.forEach(function (g) {
          box.append('<div class="px-2 pt-2 small text-muted fw-bold">' + $('<div>').text(g.label).html() + '</div>');
          g.items.forEach(function (it) {
            box.append(
              '<a class="search-item" href="' + it.url + '"><strong>' + $('<div>').text(it.title).html() +
              '</strong><div class="small text-muted">' + $('<div>').text(it.meta || '').html() + '</div></a>'
            );
          });
        });
      });
    }, 220);
  });
  $(document).on('click', function (e) {
    if (!$(e.target).closest('.search-wrap').length) {
      $('#searchResults').removeClass('open');
    }
  });

  $('[data-panel]').on('click', function (e) {
    e.stopPropagation();
    const id = $(this).data('panel');
    $('.dropdown-panel').not(id).removeClass('open');
    $(id).toggleClass('open');
  });
  $(document).on('click', function () { $('.dropdown-panel').removeClass('open'); });

  $('#quickAddForm, .ajax-form').on('submit', function (e) {
    e.preventDefault();
    const $f = $(this);
    if ($f.attr('id') === 'qa-stage') {
      const dealId = String($('#qa-stage-deal').val() || '');
      if (!dealId) {
        toast('Pick a deal.', false);
        return;
      }
      $f.attr('action', window.APP_URL + '/opportunities/' + dealId + '/stage');
    }
    const btn = $f.find('[type=submit]');
    btn.prop('disabled', true);
    const hasFile = $f.find('input[type=file]').length > 0;
    const req = hasFile
      ? $.ajax({
          url: $f.attr('action'),
          method: 'POST',
          data: new FormData($f[0]),
          processData: false,
          contentType: false,
          dataType: 'json'
        })
      : crmPost($f.attr('action'), $f.serialize());
    req.done(function (res) {
      if (res.redirect) {
        window.location = res.redirect;
        return;
      }
      toast(res.message || 'Saved.', true);
      const modal = $f.closest('.modal');
      if (modal.length) bootstrap.Modal.getInstance(modal[0])?.hide();
      if ($f.data('reload') !== false) setTimeout(() => location.reload(), 400);
    }).fail(function (xhr) {
      const err = xhr.responseJSON && xhr.responseJSON.error ? xhr.responseJSON.error : 'Could not save.';
      toast(err, false);
    }).always(function () {
      btn.prop('disabled', false);
    });
  });

  function applyTaskStatusUi($row, status) {
    const $due = $row.find('.js-task-due');
    $due.removeClass('due-overdue due-today due-later due-done due-cancelled');
    $row.toggleClass('is-done', status === 'completed');
    $row.removeClass('task-tone-overdue task-tone-today task-tone-later task-tone-done task-tone-cancelled');
    $row.find('.js-task-status').val(status).data('prev', status);
    const $icon = $row.find('.task-card-icon i');
    if (status === 'completed') {
      $due.addClass('due-done').text('Done');
      $row.addClass('task-tone-done');
      $icon.attr('class', 'bi bi-check-lg');
    } else if (status === 'cancelled') {
      $due.addClass('due-cancelled').text('Cancelled');
      $row.addClass('task-tone-cancelled');
      $icon.attr('class', 'bi bi-x-lg');
    }
  }

  $(document).on('change', '.js-task-status', function () {
    const $sel = $(this);
    const $row = $sel.closest('.task-row');
    const id = $sel.data('id');
    const status = $sel.val();
    const prev = $sel.data('prev') || 'open';
    crmPost(window.APP_URL + '/tasks/' + id, { status: status }).done(function (res) {
      toast((res && res.message) || 'Status updated.', true);
      applyTaskStatusUi($row, status);
      const filter = new URLSearchParams(window.location.search).get('status') || 'open';
      if (filter !== 'all' && filter !== status) {
        $row.slideUp(180, function () { $(this).remove(); });
      } else if (status === 'open') {
        location.reload();
      }
    }).fail(function (xhr) {
      $sel.val(prev);
      toast((xhr.responseJSON && xhr.responseJSON.error) || 'Could not update status.', false);
    });
  });

  let kanbanDrag = { id: null, href: null, fromStage: null, x: 0, y: 0, moved: false, dropped: false };
  const kanbanBoard = document.querySelector('.kanban');
  const kanbanWrap = document.querySelector('.kanban-wrap');

  function kanbanStep() {
    const col = kanbanBoard && kanbanBoard.querySelector('.kanban-col');
    return col ? col.getBoundingClientRect().width + 14 : 286;
  }

  function updateKanbanScroll() {
    if (!kanbanBoard || !kanbanWrap) {
      return;
    }
    const max = Math.max(0, kanbanBoard.scrollWidth - kanbanBoard.clientWidth);
    const left = kanbanBoard.scrollLeft;
    const overflow = max > 8;
    kanbanWrap.classList.toggle('is-overflow', overflow);
    kanbanWrap.classList.toggle('has-left', overflow && left > 8);
    kanbanWrap.classList.toggle('has-right', overflow && left < max - 8);
    kanbanWrap.querySelectorAll('[data-kanban-dir="-1"]').forEach(function (btn) {
      btn.disabled = !overflow || left <= 8;
    });
    kanbanWrap.querySelectorAll('[data-kanban-dir="1"]').forEach(function (btn) {
      btn.disabled = !overflow || left >= max - 8;
    });
    const boardBox = kanbanBoard.getBoundingClientRect();
    kanbanWrap.querySelectorAll('[data-kanban-jump]').forEach(function (chip) {
      const col = document.getElementById('kanban-stage-' + chip.getAttribute('data-kanban-jump'));
      if (!col) {
        return;
      }
      const box = col.getBoundingClientRect();
      const visible = box.right > boardBox.left + 24 && box.left < boardBox.right - 24;
      chip.classList.toggle('is-on', visible);
    });
  }

  function scrollKanban(dir) {
    if (!kanbanBoard) {
      return;
    }
    kanbanBoard.scrollBy({ left: dir * kanbanStep(), behavior: 'smooth' });
  }

  $(document).on('click', '[data-kanban-dir]', function () {
    scrollKanban(parseInt($(this).attr('data-kanban-dir'), 10) || 0);
  });
  $(document).on('click', '[data-kanban-jump]', function (e) {
    e.preventDefault();
    const col = document.getElementById('kanban-stage-' + $(this).attr('data-kanban-jump'));
    if (!kanbanBoard || !col) {
      return;
    }
    const boardBox = kanbanBoard.getBoundingClientRect();
    const colBox = col.getBoundingClientRect();
    const next = kanbanBoard.scrollLeft + (colBox.left + colBox.width / 2) - (boardBox.left + boardBox.width / 2);
    kanbanBoard.scrollTo({ left: Math.max(0, next), behavior: 'smooth' });
  });
  if (kanbanBoard) {
    kanbanBoard.addEventListener('scroll', updateKanbanScroll, { passive: true });
    kanbanBoard.addEventListener('wheel', function (e) {
      if (kanbanBoard.scrollWidth <= kanbanBoard.clientWidth + 8) {
        return;
      }
      if (Math.abs(e.deltaY) <= Math.abs(e.deltaX)) {
        return;
      }
      kanbanBoard.scrollLeft += e.deltaY;
      e.preventDefault();
    }, { passive: false });
    kanbanBoard.addEventListener('keydown', function (e) {
      if (e.key === 'ArrowRight') {
        e.preventDefault();
        scrollKanban(1);
      } else if (e.key === 'ArrowLeft') {
        e.preventDefault();
        scrollKanban(-1);
      }
    });
    let pan = null;
    kanbanBoard.addEventListener('pointerdown', function (e) {
      if (e.pointerType === 'mouse' && e.button !== 0) {
        return;
      }
      if (e.target.closest('.kanban-card, a, button')) {
        return;
      }
      pan = { x: e.clientX, left: kanbanBoard.scrollLeft };
      kanbanBoard.setPointerCapture(e.pointerId);
    });
    kanbanBoard.addEventListener('pointermove', function (e) {
      if (!pan) {
        return;
      }
      kanbanBoard.scrollLeft = pan.left - (e.clientX - pan.x);
    });
    ['pointerup', 'pointercancel', 'lostpointercapture'].forEach(function (ev) {
      kanbanBoard.addEventListener(ev, function () { pan = null; });
    });
    updateKanbanScroll();
    window.addEventListener('resize', updateKanbanScroll);
  }

  $(document).on('dragstart', '.kanban-card', function (e) {
    const $c = $(this);
    const ev = e.originalEvent;
    kanbanDrag = {
      id: $c.data('id'),
      href: $c.attr('data-href') || $c.find('.kanban-name').attr('href'),
      fromStage: $c.closest('.kanban-col').data('stage'),
      x: ev.clientX,
      y: ev.clientY,
      moved: false,
      dropped: false
    };
    ev.dataTransfer.setData('text/plain', String(kanbanDrag.id));
    ev.dataTransfer.effectAllowed = 'move';
  });
  $(document).on('drag', '.kanban-card', function (e) {
    const ev = e.originalEvent;
    if (!ev || (ev.clientX === 0 && ev.clientY === 0)) {
      return;
    }
    if (Math.abs(ev.clientX - kanbanDrag.x) > 8 || Math.abs(ev.clientY - kanbanDrag.y) > 8) {
      kanbanDrag.moved = true;
    }
  });
  $(document).on('dragover', '.kanban-col', function (e) {
    e.preventDefault();
    $(this).addClass('border border-primary');
    if (kanbanBoard) {
      const x = e.originalEvent.clientX;
      const box = kanbanBoard.getBoundingClientRect();
      if (x - box.left < 56) {
        kanbanBoard.scrollLeft -= 22;
      } else if (box.right - x < 56) {
        kanbanBoard.scrollLeft += 22;
      }
    }
  });
  $(document).on('dragleave', '.kanban-col', function () {
    $(this).removeClass('border border-primary');
  });
  $(document).on('drop', '.kanban-col', function (e) {
    e.preventDefault();
    $(this).removeClass('border border-primary');
    const stageId = $(this).data('stage');
    const isLost = String($(this).data('lost')) === '1';
    const id = kanbanDrag.id || e.originalEvent.dataTransfer.getData('text/plain');
    if (!id) {
      return;
    }
    const sameStage = String(stageId) === String(kanbanDrag.fromStage);
    if (!isLost && sameStage) {
      return;
    }
    kanbanDrag.dropped = true;
    const payload = { stage_id: stageId };
    if (isLost) {
      const reason = prompt('Why was this deal lost?');
      if (!reason) {
        kanbanDrag.dropped = false;
        return;
      }
      payload.win_loss_reason = reason;
    }
    crmPost(window.APP_URL + '/opportunities/' + id + '/stage', payload).done(function () {
      location.reload();
    }).fail(function (xhr) {
      kanbanDrag.dropped = false;
      toast((xhr.responseJSON && xhr.responseJSON.error) || 'Could not move deal.', false);
    });
  });
  $(document).on('dragend', '.kanban-card', function () {
    if (!kanbanDrag.dropped && !kanbanDrag.moved && kanbanDrag.href) {
      window.location = kanbanDrag.href;
    }
  });
  $(document).on('click', '.kanban-card', function (e) {
    if ($(e.target).closest('a').length) {
      return;
    }
    const href = $(this).attr('data-href') || $(this).find('.kanban-name').attr('href');
    if (href) {
      window.location = href;
    }
  });

  function escHtml(s) {
    return $('<div>').text(s == null ? '' : String(s)).html();
  }
  function openCalDay($cell) {
    const raw = $cell.attr('data-events');
    if (!raw) return;
    let items;
    try {
      items = JSON.parse(raw);
    } catch (err) {
      return;
    }
    const dateLabel = $cell.attr('data-date') || '';
    const count = parseInt($cell.attr('data-count') || items.length, 10);
    $('#calDayModal .modal-title').text(dateLabel);
    $('#calDayModal .cal-day-modal-count').text(count + (count === 1 ? ' item' : ' items'));
    const body = $('#calDayModalBody').empty();
    items.forEach(function (ev) {
      const time = ev.end ? (ev.time + ' – ' + ev.end) : ev.time;
      let meta = time || '';
      if (ev.location) meta += (meta ? ' · ' : '') + ev.location;
      if (ev.related) meta += (meta ? ' · ' : '') + ev.related;
      let owner = '';
      if (ev.owner) {
        owner = '<div class="cal-side-meta"><span class="task-owner-chip"><span class="task-avatar">' +
          escHtml(ev.initials) + '</span><span class="task-owner">' + escHtml(ev.owner) + '</span></span></div>';
      }
      const notes = ev.notes ? '<div class="cal-day-item-notes">' + escHtml(ev.notes) + '</div>' : '';
      body.append(
        '<div class="cal-day-item ' + escHtml(ev.cls) + '">' +
          '<div class="cal-day-item-icon"><i class="bi ' + escHtml(ev.icon) + '"></i></div>' +
          '<div class="min-w-0">' +
            '<div class="cal-day-item-title">' + escHtml(ev.title) +
              '<span class="cal-day-type">' + escHtml(ev.type) + '</span></div>' +
            '<div class="cal-day-item-meta">' + escHtml(meta) + '</div>' +
            owner + notes +
          '</div>' +
        '</div>'
      );
    });
    bootstrap.Modal.getOrCreateInstance(document.getElementById('calDayModal')).show();
  }
  $(document).on('click', '.cal-cell.has-events', function () {
    openCalDay($(this));
  });
  $(document).on('keydown', '.cal-cell.has-events', function (e) {
    if (e.key === 'Enter' || e.key === ' ') {
      e.preventDefault();
      openCalDay($(this));
    }
  });

  function syncAssignMethod() {
    const method = $('.asg-page input[name="method"]:checked').val() || 'manual';
    $('#userPick').toggle(method === 'manual');
    $('#territoryPick').toggle(method === 'territory');
  }
  $(document).on('change', '.asg-page input[name="method"]', syncAssignMethod);
  syncAssignMethod();
  $(document).on('change', '#asgSelectAll', function () {
    $('.asg-check').prop('checked', this.checked);
  });
  $(document).on('change', '.asg-check', function () {
    const all = $('.asg-check').length;
    const on = $('.asg-check:checked').length;
    $('#asgSelectAll').prop('checked', all > 0 && on === all);
  });

  $(document).on('change', '.record-file input[type=file]', function () {
    const file = this.files && this.files[0];
    const $box = $(this).closest('.record-file');
    $box.toggleClass('has-file', !!file);
    const empty = $box.find('.record-file-name').data('empty') || 'Choose a file';
    $box.find('.record-file-name').text(file ? file.name : empty);
  });

  function syncStagePaper($form) {
    const $sel = $form.find('.js-stage-select');
    if (!$sel.length) {
      return;
    }
    const $opt = $sel.find('option:selected');
    const kind = String($opt.data('paper') || '');
    const has = String($opt.data('has-paper') || '') === '1';
    const $box = $form.find('.js-stage-paper');
    const $file = $box.find('input[type=file]');
    $box.toggleClass('d-none', kind === '');
    if (!kind) {
      $file.prop('required', false);
      return;
    }
    const label = kind === 'agreement' ? 'Agreement PDF' : 'Proposal PDF';
    $box.find('.js-stage-paper-label').text(has ? ('Replace ' + label + ' (optional)') : (label + ' *'));
    $box.find('.js-stage-paper-hint').text(
      kind === 'agreement'
        ? 'Upload the agreement as a PDF (up to 8 MB).'
        : 'Upload the proposal as a PDF (up to 8 MB).'
    );
    $file.prop('required', !has);
    const $have = $box.find('.js-stage-paper-have');
    $have.toggleClass('d-none', !has);
    if (has) {
      $have.text('A ' + (kind === 'agreement' ? 'agreement' : 'proposal') + ' is already on this deal. Leave this blank or upload a new PDF.');
    }
  }
  $(document).on('change', '.js-stage-select', function () {
    syncStagePaper($(this).closest('form'));
  });
  $('.js-stage-select').each(function () {
    syncStagePaper($(this).closest('form'));
  });
})(jQuery);
