document.addEventListener('DOMContentLoaded', function () {
  document.querySelectorAll('.sidebar-dropdown').forEach(function (dropdown) {
    const trigger = dropdown.querySelector('.sidebar-dropdown-trigger');
    if (!trigger) {
      return;
    }

    trigger.addEventListener('click', function (event) {
      event.preventDefault();

      const willOpen = !dropdown.classList.contains('is-open');
      document.querySelectorAll('.sidebar-dropdown').forEach(function (item) {
        if (item !== dropdown) {
          item.classList.remove('is-open');
        }
      });

      dropdown.classList.toggle('is-open', willOpen);
    });
  });

  document.querySelectorAll('.customer-pop-menu, .customer-pop-submenu, [data-customer-view-menu]').forEach(function (menu) {
    menu.addEventListener('click', function (event) {
      event.stopPropagation();
    });
  });

  const customerViewToggle = document.querySelector('[data-customer-view-toggle]');
  const customerViewMenu = document.querySelector('[data-customer-view-menu]');
  const customerViewSearch = document.querySelector('[data-customer-view-search]');
  const customerViewOptions = Array.from(document.querySelectorAll('[data-customer-view-option]'));

  if (customerViewToggle && customerViewMenu) {
    customerViewToggle.addEventListener('click', function (event) {
      event.stopPropagation();
      const isHidden = customerViewMenu.hidden;
      customerViewMenu.hidden = !isHidden;
      customerViewToggle.setAttribute('aria-expanded', isHidden ? 'true' : 'false');
      if (isHidden && customerViewSearch) {
        window.setTimeout(function () {
          customerViewSearch.focus();
        }, 20);
      }
    });
  }

  if (customerViewSearch && customerViewOptions.length) {
    customerViewSearch.addEventListener('input', function () {
      const query = customerViewSearch.value.trim().toLowerCase();
      customerViewOptions.forEach(function (option) {
        const label = option.getAttribute('data-customer-view-label') || '';
        option.hidden = query !== '' && label.indexOf(query) === -1;
      });
    });
  }

  document.querySelectorAll('[data-customer-tab]').forEach(function (tabButton) {
    tabButton.addEventListener('click', function () {
      const target = tabButton.getAttribute('data-customer-tab');
      document.querySelectorAll('[data-customer-tab]').forEach(function (button) {
        button.classList.toggle('is-active', button === tabButton);
      });
      document.querySelectorAll('[data-customer-panel]').forEach(function (panel) {
        panel.classList.toggle('is-active', panel.getAttribute('data-customer-panel') === target);
      });
    });
  });

  const moreDetailsToggle = document.querySelector('[data-customer-more]');
  const moreDetailsFields = document.querySelector('[data-customer-extra-fields]');
  if (moreDetailsToggle && moreDetailsFields) {
    moreDetailsToggle.addEventListener('click', function (event) {
      event.preventDefault();
      const isHidden = moreDetailsFields.hasAttribute('hidden');
      if (isHidden) {
        moreDetailsFields.removeAttribute('hidden');
        moreDetailsToggle.textContent = 'Show fewer details';
      } else {
        moreDetailsFields.setAttribute('hidden', '');
        moreDetailsToggle.textContent = 'Add more details';
      }
    });
  }

  const copyBillingAddress = document.querySelector('[data-copy-billing-address]');
  if (copyBillingAddress) {
    copyBillingAddress.addEventListener('click', function (event) {
      event.preventDefault();
      const pairs = [
        ['billing_attention', 'shipping_attention'],
        ['billing_country', 'shipping_country'],
        ['billing_address_1', 'shipping_address_1'],
        ['billing_address_2', 'shipping_address_2'],
        ['billing_city', 'shipping_city'],
        ['billing_state', 'shipping_state'],
        ['billing_pin', 'shipping_pin'],
        ['billing_phone', 'shipping_phone'],
        ['billing_fax', 'shipping_fax']
      ];

      pairs.forEach(function (pair) {
        const source = document.querySelector('[name="' + pair[0] + '"]');
        const target = document.querySelector('[name="' + pair[1] + '"]');
        if (source && target) {
          target.value = source.value;
        }
      });
    });
  }

  document.querySelectorAll('[data-menu-toggle]').forEach(function (toggle) {
    toggle.addEventListener('click', function (event) {
      event.stopPropagation();
      const menu = document.getElementById(toggle.getAttribute('data-menu-toggle'));
      document.querySelectorAll('.customer-pop-menu').forEach(function (item) {
        if (item !== menu) {
          item.hidden = true;
        }
      });
      if (menu) {
        menu.hidden = !menu.hidden;
      }
    });
  });

  document.querySelectorAll('[data-menu-child]').forEach(function (toggle) {
    toggle.addEventListener('click', function (event) {
      event.stopPropagation();
      const submenuId = toggle.getAttribute('data-menu-child');
      document.querySelectorAll('.customer-pop-submenu').forEach(function (item) {
        item.hidden = item.id !== submenuId || !item.hidden ? item.id !== submenuId : false;
      });
      const submenu = document.getElementById(submenuId);
      if (submenu) {
        submenu.hidden = !submenu.hidden;
      }
    });

    toggle.addEventListener('mouseenter', function () {
      const submenuId = toggle.getAttribute('data-menu-child');
      document.querySelectorAll('.customer-pop-submenu').forEach(function (item) {
        item.hidden = item.id !== submenuId;
      });
    });
  });

  document.addEventListener('click', function () {
    document.querySelectorAll('.customer-pop-menu, .customer-pop-submenu, [data-customer-view-menu]').forEach(function (menu) {
      menu.hidden = true;
    });
    if (customerViewToggle) {
      customerViewToggle.setAttribute('aria-expanded', 'false');
    }
  });

  const customerSearch = document.querySelector('.billing-search-shell input[type="search"]');
  const customerRows = Array.from(document.querySelectorAll('[data-customer-row]'));
  const customerList = document.querySelector('[data-customer-list]');
  if (customerSearch && customerRows.length) {
    customerSearch.addEventListener('input', function () {
      const query = customerSearch.value.trim().toLowerCase();
      let visibleCount = 0;
      customerRows.forEach(function (row) {
        const haystack = (row.getAttribute('data-customer-name') || '') + ' ' + (row.getAttribute('data-customer-email') || '');
        const matches = query === '' || haystack.indexOf(query) !== -1;
        row.hidden = !matches;
        if (matches) {
          visibleCount += 1;
        }
      });

      if (customerList) {
        customerList.classList.toggle('is-filter-empty', visibleCount === 0);
      }
    });
  }

  document.querySelectorAll('[data-customer-detail-tab]').forEach(function (tab) {
    tab.addEventListener('click', function (event) {
      event.preventDefault();
      const target = tab.getAttribute('data-customer-detail-tab');
      document.querySelectorAll('[data-customer-detail-tab]').forEach(function (link) {
        link.classList.toggle('is-active', link === tab);
      });
      document.querySelectorAll('[data-customer-detail-panel-name]').forEach(function (panel) {
        panel.classList.toggle('is-active', panel.getAttribute('data-customer-detail-panel-name') === target);
      });
    });
  });

  document.querySelectorAll('[data-customer-collapse-toggle]').forEach(function (button) {
    button.addEventListener('click', function () {
      const block = button.closest('.customer-info-block');
      if (!block) {
        return;
      }
      const content = block.querySelector('[data-customer-collapse-content]');
      if (!content) {
        return;
      }
      const collapsed = content.hasAttribute('hidden');
      if (collapsed) {
        content.removeAttribute('hidden');
      } else {
        content.setAttribute('hidden', '');
      }
      block.classList.toggle('is-collapsed', !collapsed);
    });
  });

  const customerClose = document.querySelector('[data-customer-close]');
  if (customerClose) {
    customerClose.addEventListener('click', function () {
      const detailPanel = document.querySelector('[data-customer-detail-panel]');
      if (detailPanel) {
        detailPanel.classList.toggle('is-hidden');
      }
      customerRows.forEach(function (row) {
        row.classList.remove('is-active');
      });
    });
  }

  const refreshListButton = document.querySelector('[data-customer-refresh]');
  if (refreshListButton) {
    refreshListButton.addEventListener('click', function () {
      window.location.reload();
    });
  }

  document.querySelectorAll('[data-customer-sort]').forEach(function (button) {
    button.addEventListener('click', function () {
      if (!customerList) {
        return;
      }
      const sortKey = button.getAttribute('data-customer-sort');
      const sortedRows = customerRows.slice().sort(function (a, b) {
        if (sortKey === 'receivable') {
          return parseFloat(b.getAttribute('data-customer-receivable') || '0') - parseFloat(a.getAttribute('data-customer-receivable') || '0');
        }
        if (sortKey === 'created') {
          return new Date(b.getAttribute('data-customer-created') || 0) - new Date(a.getAttribute('data-customer-created') || 0);
        }
        const attr = sortKey === 'email' ? 'data-customer-email' : 'data-customer-name';
        return (a.getAttribute(attr) || '').localeCompare(b.getAttribute(attr) || '');
      });
      sortedRows.forEach(function (row) {
        customerList.appendChild(row);
      });
      document.querySelectorAll('.customer-pop-menu, .customer-pop-submenu').forEach(function (menu) {
        menu.hidden = true;
      });
    });
  });

  document.querySelectorAll('[data-customer-note]').forEach(function (button) {
    button.addEventListener('click', function (event) {
      event.preventDefault();
      const message = button.getAttribute('data-customer-note');
      if (!message) {
        return;
      }
      let note = document.querySelector('[data-customer-runtime-note]');
      if (!note) {
        note = document.createElement('div');
        note.className = 'customer-runtime-note';
        note.setAttribute('data-customer-runtime-note', '');
        document.body.appendChild(note);
      }
      note.textContent = message;
      note.classList.add('is-visible');
      window.clearTimeout(note._hideTimer);
      note._hideTimer = window.setTimeout(function () {
        note.classList.remove('is-visible');
      }, 2200);
    });
  });

  const attachmentModal = document.querySelector('[data-customer-attachment-modal]');
  const attachmentOpen = document.querySelector('[data-customer-attachment-open]');

  document.querySelectorAll('[data-file-trigger]').forEach(function (button) {
    button.addEventListener('click', function () {
      const input = document.getElementById(button.getAttribute('data-file-trigger'));
      if (input) {
        input.click();
      }
    });
  });

  document.querySelectorAll('input[type="file"]').forEach(function (input) {
    input.addEventListener('change', function () {
      const listId = input.id ? input.id + 'List' : '';
      const list = listId ? document.getElementById(listId) : null;
      if (!list) {
        return;
      }
      const names = Array.from(input.files || []).map(function (file) {
        return file.name;
      });
      list.textContent = names.length ? names.join(', ') : '';
    });
  });

  // Clear invalid styling on input to prevent red text on typing
  document.addEventListener('input', function(event) {
    if (event.target.matches('.customer-form-grid input, .customer-form-grid select, .customer-form-grid textarea')) {
      if (event.target.classList.contains('is-invalid')) {
        // Check if input is now valid (non-empty for required, valid email etc.)
        const isRequired = event.target.hasAttribute('required');
        const value = event.target.value.trim();
        if (!isRequired || value !== '') {
          event.target.classList.remove('is-invalid');
        }
      }
    }
  }, true);
  const attachmentClose = document.querySelector('[data-customer-attachment-close]');
  const attachmentOptionsToggle = document.querySelector('[data-customer-attachment-options]');
  const attachmentOptionsMenu = document.querySelector('[data-customer-attachment-options-menu]');

  if (attachmentOpen && attachmentModal) {
    attachmentOpen.addEventListener('click', function () {
      attachmentModal.hidden = false;
    });
  }

  if (attachmentClose && attachmentModal) {
    attachmentClose.addEventListener('click', function () {
      attachmentModal.hidden = true;
      if (attachmentOptionsMenu) {
        attachmentOptionsMenu.hidden = true;
      }
    });
  }

  if (attachmentOptionsToggle && attachmentOptionsMenu) {
    attachmentOptionsToggle.addEventListener('click', function () {
      attachmentOptionsMenu.hidden = !attachmentOptionsMenu.hidden;
    });
  }

  if (attachmentModal) {
    attachmentModal.addEventListener('click', function (event) {
      if (event.target === attachmentModal) {
        attachmentModal.hidden = true;
        if (attachmentOptionsMenu) {
          attachmentOptionsMenu.hidden = true;
        }
      }
    });
  }

  const customViewForm = document.querySelector('[data-custom-view-form]');
  const criteriaList = document.querySelector('[data-criteria-list]');
  const criteriaCountField = document.querySelector('[data-criteria-count]');

  function updateCriterionNumbers() {
    if (!criteriaList) {
      return;
    }

    const rows = Array.from(criteriaList.querySelectorAll('[data-criterion-row]'));
    rows.forEach(function (row, index) {
      const number = row.querySelector('.customer-criterion-number');
      if (number) {
        number.textContent = String(index + 1);
      }
    });

    if (criteriaCountField) {
      criteriaCountField.value = String(rows.length);
    }
  }

  function buildCriterionLogicRow() {
    const logicRow = document.createElement('div');
    logicRow.className = 'customer-criteria-logic-row';

    const select = document.createElement('select');
    select.name = 'criteria_logic';

    const andOption = document.createElement('option');
    andOption.value = 'AND';
    andOption.textContent = 'AND';
    select.appendChild(andOption);

    const orOption = document.createElement('option');
    orOption.value = 'OR';
    orOption.textContent = 'OR';
    select.appendChild(orOption);

    logicRow.appendChild(select);
    return logicRow;
  }

  function buildCriterionRow() {
    const row = document.createElement('div');
    row.className = 'customer-criterion-row';
    row.setAttribute('data-criterion-row', '');
    row.innerHTML =
      '<div class="customer-criterion-number"></div>' +
      '<select name="criteria_field[]">' +
      '<option value="">Select a field</option>' +
      '<option value="display_name">Display Name</option>' +
      '<option value="company_name">Company Name</option>' +
      '<option value="email">Email</option>' +
      '<option value="work_phone">Work Phone</option>' +
      '<option value="customer_type">Customer Type</option>' +
      '<option value="portal_status">Portal Status</option>' +
      '</select>' +
      '<select name="criteria_comparator[]">' +
      '<option value="">Select a comparator</option>' +
      '<option value="contains">contains</option>' +
      '<option value="is">is</option>' +
      '<option value="is_not">is not</option>' +
      '<option value="starts_with">starts with</option>' +
      '<option value="ends_with">ends with</option>' +
      '</select>' +
      '<input type="text" name="criteria_value[]" value="">' +
      '<button class="customer-criterion-add" type="button" data-criterion-add><i class="fa-solid fa-plus"></i></button>' +
      '<button class="customer-criterion-remove" type="button" data-criterion-remove><i class="fa-regular fa-trash-can"></i></button>';
    return row;
  }

  function addCriterionRow(afterRow) {
    if (!criteriaList) {
      return;
    }

    const newRow = buildCriterionRow();
    const rows = Array.from(criteriaList.querySelectorAll('[data-criterion-row]'));
    if (rows.length > 0) {
      const logicRow = buildCriterionLogicRow();
      if (afterRow && afterRow.parentNode === criteriaList) {
        criteriaList.insertBefore(logicRow, afterRow.nextSibling);
        criteriaList.insertBefore(newRow, logicRow.nextSibling);
      } else {
        criteriaList.appendChild(logicRow);
        criteriaList.appendChild(newRow);
      }
    } else {
      criteriaList.appendChild(newRow);
    }

    updateCriterionNumbers();
  }

  if (criteriaList) {
    criteriaList.addEventListener('click', function (event) {
      const addButton = event.target.closest('[data-criterion-add]');
      const removeButton = event.target.closest('[data-criterion-remove]');

      if (addButton) {
        event.preventDefault();
        addCriterionRow(addButton.closest('[data-criterion-row]'));
        return;
      }

      if (removeButton) {
        event.preventDefault();
        const row = removeButton.closest('[data-criterion-row]');
        if (!row) {
          return;
        }

        const rows = Array.from(criteriaList.querySelectorAll('[data-criterion-row]'));
        if (rows.length <= 1) {
          row.querySelectorAll('input, select').forEach(function (field) {
            field.value = '';
          });
          return;
        }

        const next = row.nextElementSibling;
        const prev = row.previousElementSibling;
        row.remove();

        if (next && next.classList.contains('customer-criteria-logic-row')) {
          next.remove();
        } else if (prev && prev.classList.contains('customer-criteria-logic-row')) {
          prev.remove();
        }

        updateCriterionNumbers();
      }
    });
  }

  const addCriterionLink = document.querySelector('[data-criterion-add-link]');
  if (addCriterionLink) {
    addCriterionLink.addEventListener('click', function (event) {
      event.preventDefault();
      addCriterionRow(null);
    });
  }

  if (customViewForm) {
    updateCriterionNumbers();
  }

  const pageOverlay = document.querySelector('[data-drawer-overlay]');
  const drawerTriggers = document.querySelectorAll('[data-drawer-target]');
  const drawerClosers = document.querySelectorAll('[data-drawer-close]');
  const drawers = document.querySelectorAll('.billing-org-drawer, .billing-side-drawer');
  let activeDrawer = null;

  function setExpandedState(drawerId, expanded) {
    drawerTriggers.forEach(function (trigger) {
      if (trigger.getAttribute('data-drawer-target') === drawerId) {
        trigger.setAttribute('aria-expanded', expanded ? 'true' : 'false');
      }
    });
  }

  function closeDrawer() {
    if (!activeDrawer) {
      return;
    }

    activeDrawer.classList.remove('is-open');
    activeDrawer.setAttribute('aria-hidden', 'true');
    setExpandedState(activeDrawer.id, false);
    activeDrawer = null;

    if (pageOverlay) {
      pageOverlay.hidden = true;
    }

    document.body.classList.remove('billing-drawer-open');
  }

  function openDrawer(drawer) {
    if (!drawer) {
      return;
    }

    if (activeDrawer && activeDrawer !== drawer) {
      closeDrawer();
    }

    activeDrawer = drawer;
    drawer.classList.add('is-open');
    drawer.setAttribute('aria-hidden', 'false');
    setExpandedState(drawer.id, true);

    if (pageOverlay) {
      pageOverlay.hidden = false;
    }

    document.body.classList.add('billing-drawer-open');
  }

  drawerTriggers.forEach(function (trigger) {
    trigger.addEventListener('click', function () {
      const drawer = document.getElementById(trigger.getAttribute('data-drawer-target'));
      if (!drawer) {
        return;
      }

      if (activeDrawer === drawer) {
        closeDrawer();
        return;
      }

      openDrawer(drawer);
    });
  });

  drawerClosers.forEach(function (button) {
    button.addEventListener('click', closeDrawer);
  });

  if (pageOverlay) {
    pageOverlay.addEventListener('click', closeDrawer);
  }

  document.addEventListener('keydown', function (event) {
    if (event.key === 'Escape') {
      closeDrawer();
    }
  });

  const tourRoot = document.querySelector('[data-tour-root]');
  if (!tourRoot) {
    return;
  }

  const enabled = tourRoot.getAttribute('data-tour-enabled') === '1';
  if (!enabled) {
    return;
  }

  document.body.classList.add('tour-mode');

  const overlay = document.querySelector('[data-tour-overlay]');
  const card = document.querySelector('[data-tour-card]');
  const stepLabel = document.querySelector('[data-tour-step]');
  const title = document.querySelector('[data-tour-title]');
  const body = document.querySelector('[data-tour-body]');
  const previous = document.querySelector('[data-tour-prev]');
  const next = document.querySelector('[data-tour-next]');
  const skip = document.querySelector('[data-tour-skip]');

  if (!overlay || !card || !stepLabel || !title || !body || !previous || !next || !skip) {
    return;
  }

  const steps = [
    {
      selector: '[data-tour="welcome"]',
      title: 'Keep tabs on everything',
      body: 'View key metrics from the dashboard, set up your organization from Getting Started, or catch up on recent updates to Zoho Billing.',
      position: 'left',
    },
    {
      selector: '[data-tour="customers"]',
      title: 'Experience simplified customer management',
      body: 'Create and manage customers, view their transactions, and send emails. Find customers easily using filters and advanced search options.',
      position: 'left',
    },
    {
      selector: '[data-tour="catalog"]',
      title: 'Your goods and services go here',
      body: 'Create Invoices for one-time billing, and Subscriptions for recurring billing. Offer credits and refunds using Credit Notes.',
      position: 'left',
    },
    {
      selector: '[data-tour="sales"]',
      title: 'Bill your customers and manage credits',
      body: 'Create invoices, subscriptions, and delivery challans from the sales section while keeping collections on track.',
      position: 'left',
    },
    {
      selector: '[data-tour="timetracking"]',
      title: 'Manage multiple projects with ease',
      body: 'Create projects, track work-hours, and set hourly rates to bill your customers accordingly.',
      position: 'left',
    },
    {
      selector: '[data-tour="settings"]',
      title: 'Make Zoho Billing yours',
      body: 'Explore a wide range of settings and tailor-make the billing experience for your organization.',
      position: 'right',
    },
    {
      selector: '[data-tour="help"]',
      title: 'Find help and support',
      body: 'Read up on help resources and useful articles. You can also request features or contact the support team.',
      position: 'right',
    }
  ];

  let current = 0;
  let highlighted = null;

  function clearHighlight() {
    if (highlighted) {
      highlighted.classList.remove('tour-highlight');
      highlighted = null;
    }
  }

  function positionCard(target, position) {
    const rect = target.getBoundingClientRect();
    const cardWidth = Math.min(420, window.innerWidth - 30);
    const cardHeight = 350;
    let top = Math.max(18, rect.top + window.scrollY);
    let left;

    if (position === 'right') {
      left = window.scrollX + Math.min(window.innerWidth - cardWidth - 18, rect.right + 18);
    } else {
      left = window.scrollX + Math.max(18, rect.left - cardWidth - 18);
    }

    if (left < 18) {
      left = 18;
    }

    if (top + cardHeight > window.scrollY + window.innerHeight - 18) {
      top = window.scrollY + window.innerHeight - cardHeight - 18;
    }

    card.style.left = left + 'px';
    card.style.top = top + 'px';
  }

  function render() {
    clearHighlight();

    const step = steps[current];
    const target = document.querySelector(step.selector);
    if (!target) {
      closeTour();
      return;
    }

    highlighted = target;
    highlighted.classList.add('tour-highlight');

    overlay.classList.add('is-visible');
    card.classList.add('is-visible');
    stepLabel.textContent = 'Step ' + (current + 1) + ' / ' + steps.length;
    title.textContent = step.title;
    body.textContent = step.body;
    previous.style.visibility = current === 0 ? 'hidden' : 'visible';
    next.textContent = current === steps.length - 1 ? 'Finish' : 'Next';

    positionCard(target, step.position);
  }

  function closeTour() {
    clearHighlight();
    document.body.classList.remove('tour-mode');
    overlay.classList.remove('is-visible');
    card.classList.remove('is-visible');
    fetch('dashboard.php?dismiss_tour=1', { credentials: 'same-origin' }).catch(function () {});
  }

  previous.addEventListener('click', function () {
    if (current > 0) {
      current -= 1;
      render();
    }
  });

  next.addEventListener('click', function () {
    if (current < steps.length - 1) {
      current += 1;
      render();
      return;
    }

    closeTour();
  });

  skip.addEventListener('click', closeTour);
  overlay.addEventListener('click', closeTour);
  window.addEventListener('resize', render);

  render();
});

document.addEventListener('DOMContentLoaded', function () {
  function parseDataset(node, key) {
    const raw = node.getAttribute(key);
    if (!raw) {
      return null;
    }

    try {
      return JSON.parse(raw);
    } catch (error) {
      return null;
    }
  }

  function buildChartShell(node, labels) {
    const shell = document.createElement('div');
    shell.className = 'dashboard-chart-shell';

    const grid = document.createElement('div');
    grid.className = 'dashboard-chart-grid';
    for (let i = 0; i < 5; i += 1) {
      grid.appendChild(document.createElement('span'));
    }

    const labelRow = document.createElement('div');
    labelRow.className = 'dashboard-chart-labels';
    labelRow.style.gridTemplateColumns = 'repeat(' + Math.max(labels.length, 1) + ', minmax(0, 1fr))';
    labels.forEach(function (label) {
      const labelNode = document.createElement('span');
      labelNode.textContent = label;
      labelRow.appendChild(labelNode);
    });

    shell.appendChild(grid);
    shell.appendChild(labelRow);
    return { shell: shell, labels: labelRow };
  }

  function renderLineChart(node, labels, series) {
    const hasData = series.some(function (entry) {
      return (entry.values || []).some(function (value) { return Number(value || 0) > 0; });
    });
    if (!hasData) {
      return;
    }

    const chartParts = buildChartShell(node, labels);
    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttribute('viewBox', '0 0 100 100');
    svg.setAttribute('preserveAspectRatio', 'none');
    svg.setAttribute('class', 'dashboard-chart-svg');

    let maxValue = 0;
    series.forEach(function (entry) {
      (entry.values || []).forEach(function (value) {
        maxValue = Math.max(maxValue, Number(value || 0));
      });
    });
    if (maxValue <= 0) {
      maxValue = 1;
    }

    series.forEach(function (entry) {
      const values = (entry.values || []).map(function (value) { return Number(value || 0); });
      const points = values.map(function (value, index) {
        const x = values.length === 1 ? 50 : (index / (values.length - 1)) * 100;
        const y = 92 - ((value / maxValue) * 82);
        return x.toFixed(2) + ',' + y.toFixed(2);
      }).join(' ');

      if (entry.fill) {
        const area = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
        const areaPoints = '0,92 ' + points + ' 100,92';
        area.setAttribute('points', areaPoints);
        area.setAttribute('fill', entry.fill);
        svg.appendChild(area);
      }

      const polyline = document.createElementNS('http://www.w3.org/2000/svg', 'polyline');
      polyline.setAttribute('points', points);
      polyline.setAttribute('fill', 'none');
      polyline.setAttribute('stroke', entry.color || '#2d6cdf');
      polyline.setAttribute('stroke-width', '2.4');
      polyline.setAttribute('stroke-linecap', 'round');
      polyline.setAttribute('stroke-linejoin', 'round');
      svg.appendChild(polyline);

      values.forEach(function (value, index) {
        const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
        const x = values.length === 1 ? 50 : (index / (values.length - 1)) * 100;
        const y = 92 - ((value / maxValue) * 82);
        circle.setAttribute('cx', x.toFixed(2));
        circle.setAttribute('cy', y.toFixed(2));
        circle.setAttribute('r', '1.6');
        circle.setAttribute('fill', entry.color || '#2d6cdf');
        svg.appendChild(circle);
      });
    });

    chartParts.shell.appendChild(svg);
    node.appendChild(chartParts.shell);
  }

  function renderBarChart(node, labels, series, grouped) {
    const hasData = series.some(function (entry) {
      return (entry.values || []).some(function (value) { return Number(value || 0) > 0; });
    });
    if (!hasData) {
      if (!node.querySelector('.dashboard-chart-empty')) {
        const empty = document.createElement('div');
        empty.className = 'dashboard-chart-empty';
        empty.textContent = 'No data found.';
        node.appendChild(empty);
      }
      return;
    }

    const chartParts = buildChartShell(node, labels);
    const groups = document.createElement('div');
    groups.className = 'dashboard-bar-groups';
    groups.style.gridTemplateColumns = 'repeat(' + Math.max(labels.length, 1) + ', minmax(0, 1fr))';

    let maxValue = 0;
    series.forEach(function (entry) {
      (entry.values || []).forEach(function (value) {
        maxValue = Math.max(maxValue, Number(value || 0));
      });
    });
    if (maxValue <= 0) {
      maxValue = 1;
    }

    labels.forEach(function (_, labelIndex) {
      const group = document.createElement('div');
      group.className = 'dashboard-bar-group';

      series.forEach(function (entry, seriesIndex) {
        const bar = document.createElement('span');
        const value = Number((entry.values || [])[labelIndex] || 0);
        const heightPercent = Math.max(2, (value / maxValue) * 100);
        bar.className = 'dashboard-bar';
        bar.style.height = heightPercent + '%';
        bar.style.background = entry.color || (seriesIndex === 0 ? '#2d6cdf' : '#f8cf6f');
        if (!grouped && seriesIndex > 0) {
          return;
        }
        if (grouped) {
          bar.style.width = '18px';
        }
        group.appendChild(bar);
      });

      groups.appendChild(group);
    });

    chartParts.shell.appendChild(groups);
    node.appendChild(chartParts.shell);
  }

  document.querySelectorAll('[data-chart]').forEach(function (node) {
    const labels = parseDataset(node, 'data-labels') || [];
    const series = parseDataset(node, 'data-series') || [];
    const type = node.getAttribute('data-chart');

    if (!labels.length || !series.length) {
      return;
    }

    if (type === 'line') {
      renderLineChart(node, labels, series);
      return;
    }

    if (type === 'bars') {
      renderBarChart(node, labels, series.slice(0, 1), false);
      return;
    }

    if (type === 'bars-grouped') {
      renderBarChart(node, labels, series, true);
    }
  });

  document.querySelectorAll('[data-dashboard-range-switch]').forEach(function (select) {
    select.addEventListener('change', function () {
      const url = new URL(window.location.href);
      url.searchParams.set('tab', 'dashboard');
      url.searchParams.set('range', select.value || '12');
      window.location.href = url.toString();
    });
  });

  const banner = document.querySelector('[data-dashboard-banner]');
  const bannerDismiss = document.querySelector('[data-dashboard-banner-dismiss]');
  const bannerStorageKey = 'billing-dashboard-banner-dismissed';
  if (banner && window.localStorage && localStorage.getItem(bannerStorageKey) === '1') {
    banner.hidden = true;
  }

  if (banner && bannerDismiss) {
    bannerDismiss.addEventListener('click', function () {
      banner.hidden = true;
      if (window.localStorage) {
        localStorage.setItem(bannerStorageKey, '1');
      }
    });
  }
});
