/* ============================================================
   app.js — Tamasa application controller
   ------------------------------------------------------------
   State, rendering, events. Built modular for CRM expansion.
   ============================================================ */
(function () {
  'use strict';

  var $ = UI.$, $$ = UI.$$, el = UI.el, clear = UI.clear, esc = UI.esc;
  var debounce = UI.debounce;

  /* =========================================================
     STATE
     ========================================================= */
  var state = {
    contacts: [],          // all contacts (in memory; IndexedDB is source of truth)
    tagMap: {},            // tagId -> tag definition {id,name,color}
    view: 'all',           // 'all' | 'starred' | 'tag:<id>'
    query: '',             // search query (raw)
    sort: 'name-asc',
    editingId: null,       // id of contact being edited
    formTags: [],          // tags in current form
    formBirthday: null     // {jy,jm,jd} for current form
  };

  /* =========================================================
     INIT
     ========================================================= */
  document.addEventListener('DOMContentLoaded', init);

  function init() {
    DB.open()
      .then(loadTags)
      .then(loadContacts)
      .then(function () {
        renderSidebar();
        render();
        bindGlobalEvents();
      })
      .catch(function (err) {
        console.error('Init failed', err);
        UI.toast('خطا در باز کردن پایگاه داده', 'error');
      });
  }

  function loadContacts() {
    return DB.Contacts.getAll().then(function (list) {
      state.contacts = list;
    });
  }

  function loadTags() {
    return DB.Tags.getAll().then(function (tags) {
      state.tagMap = {};
      tags.forEach(function (t) { state.tagMap[t.id] = t; });
    });
  }

  /* =========================================================
     EVENTS — global wiring
     ========================================================= */
  function bindGlobalEvents() {
    // Sidebar nav
    $$('.nav-item').forEach(function (btn) {
      btn.addEventListener('click', function () {
        setView(btn.dataset.view);
      });
    });

    // New contact
    $('#btn-new-contact').addEventListener('click', function () { openContactForm(); });
    document.addEventListener('click', function (e) {
      var t = e.target.closest('[data-action="empty-new"]');
      if (t) openContactForm();
    });

    // Search
    var searchInput = $('#search-input');
    var searchClear = $('#search-clear');
    var onSearch = debounce(function () {
      state.query = searchInput.value.trim();
      searchClear.hidden = !state.query;
      render();
    }, 90);
    searchInput.addEventListener('input', onSearch);
    searchClear.addEventListener('click', function () {
      searchInput.value = ''; state.query = ''; searchClear.hidden = true;
      searchInput.focus(); render();
    });

    // Sort
    $('#sort-select').addEventListener('change', function (e) {
      state.sort = e.target.value; render();
    });

    // Sidebar data actions
    $('#btn-import').addEventListener('click', function () { $('#file-import').click(); });
    $('#btn-export').addEventListener('click', exportExcel);
    $('#btn-backup').addEventListener('click', backupJSON);
    $('#btn-restore').addEventListener('click', function () { $('#file-restore').click(); });

    // File inputs
    $('#file-import').addEventListener('change', handleImport);
    $('#file-restore').addEventListener('change', handleRestore);

    // Modal close (delegated)
    document.addEventListener('click', function (e) {
      if (e.target.closest('[data-close]')) {
        var modal = e.target.closest('.modal');
        if (modal) UI.closeModal(modal);
        var dp = $('#datepicker');
        if (dp) dp.hidden = true;
      }
    });

    // Esc closes everything
    document.addEventListener('keydown', function (e) {
      if (e.key === 'Escape') {
        var dp = $('#datepicker');
        if (dp && !dp.hidden) { dp.hidden = true; return; }
        UI.closeAllModals();
      }
    });

    // Contact grid clicks (delegated)
    $('#contacts-grid').addEventListener('click', onGridClick);

    // Form wiring
    bindContactForm();

    // Detail modal wiring
    bindDetailModal();
  }

  /* =========================================================
     VIEW switching
     ========================================================= */
  function setView(view) {
    state.view = view;
    $$('.nav-item').forEach(function (b) {
      b.classList.toggle('nav-item--active', b.dataset.view === view);
    });
    $$('.tag-pill').forEach(function (p) {
      p.classList.toggle('tag-pill--active', p.dataset.view === view);
    });
    render();
  }

  /* =========================================================
     RENDERING
     ========================================================= */

  // Filter + sort -> visible list
  function getVisibleContacts() {
    var list = state.contacts.slice();

    // 1. View filter
    if (state.view === 'starred') {
      list = list.filter(function (c) { return c.starred; });
    } else if (state.view.indexOf('tag:') === 0) {
      var tagId = state.view.slice(4);
      list = list.filter(function (c) { return (c.tags || []).indexOf(tagId) !== -1; });
    }

    // 2. Search filter
    if (state.query) {
      var q = DB.normalizeQuery(state.query);
      list = list.filter(function (c) {
        return (c.searchKey || '').indexOf(q) !== -1;
      });
    }

    // 3. Sort
    list.sort(getComparator(state.sort));
    return list;
  }

  function getComparator(sort) {
    switch (sort) {
      case 'name-asc':  return nameCmp(true);
      case 'name-desc': return nameCmp(false);
      case 'created-desc': return numCmp('createdAt', false);
      case 'created-asc':  return numCmp('createdAt', true);
      case 'updated-desc': return numCmp('updatedAt', false);
      default: return nameCmp(true);
    }
  }
  function nameCmp(asc) {
    var dir = asc ? 1 : -1;
    return function (a, b) {
      var pa = persianCollator(a.lastName || a.fullName || '');
      var pb = persianCollator(b.lastName || b.fullName || '');
      if (pa < pb) return -1 * dir;
      if (pa > pb) return 1 * dir;
      return 0;
    };
  }
  // Convert to a sortable Persian string (Persian letters sort before latin)
  function persianCollator(s) {
    return String(s || '').trim().toLowerCase();
  }
  function numCmp(key, asc) {
    var dir = asc ? 1 : -1;
    return function (a, b) {
      return ((a[key] || 0) - (b[key] || 0)) * dir;
    };
  }

  function render() {
    var list = getVisibleContacts();
    var grid = $('#contacts-grid');

    // Title + counts
    var titleMap = { 'all': 'همه مخاطبین', 'starred': 'علاقه‌مندی‌ها' };
    var title;
    if (state.view.indexOf('tag:') === 0) {
      var tag = state.tagMap[state.view.slice(4)];
      title = tag ? 'برچسب: ' + tag.name : 'برچسب';
    } else {
      title = titleMap[state.view] || 'مخاطبین';
    }
    $('#view-title').textContent = title;
    var countLabel = Jalali.toPersianDigits(toFa(list.length)) + ' مخاطب';
    $('#view-count').textContent = countLabel;

    // Empty state
    var empty = $('#empty-state');
    if (list.length === 0) {
      grid.hidden = true;
      empty.hidden = false;
      // tweak empty message for search/no-contacts
      var h2 = empty.querySelector('h2');
      var p = empty.querySelector('p');
      if (state.query) {
        h2.textContent = 'نتیجه‌ای یافت نشد';
        p.textContent = 'برای «' + state.query + '» مخاطبی پیدا نشد.';
      } else if (state.contacts.length === 0) {
        h2.textContent = 'هنوز مخاطبی ثبت نشده';
        p.textContent = 'اولین مخاطب خود را اضافه کنید یا از Excel وارد کنید.';
      } else {
        h2.textContent = 'مخاطبی در این بخش نیست';
        p.textContent = 'یک بخش دیگر را انتخاب کنید یا جستجو را تغییر دهید.';
      }
      return;
    }
    grid.hidden = false;
    empty.hidden = true;

    // Render cards (DocumentFragment for performance)
    var frag = document.createDocumentFragment();
    list.forEach(function (c) { frag.appendChild(renderCard(c)); });
    clear(grid);
    grid.appendChild(frag);
  }

  function toFa(n) { return String(n); } // count then digit-converted

  function renderCard(c) {
    var card = el('article', { class: 'contact-card', dataset: { id: c.id } });

    // Top: avatar + name + star
    var top = el('div', { class: 'contact-card__top' });
    var ini = UI.initials(c.firstName, c.lastName, c.fullName);
    var avatar = el('div', { class: 'avatar avatar--sm', style: UI.avatarStyle(c.lastName || c.firstName || c.id), text: ini });
    top.appendChild(avatar);

    var main = el('div', { class: 'contact-card__main' });
    main.appendChild(el('div', { class: 'contact-card__name', text: c.fullName || 'بدون نام' }));
    var subBits = [];
    if (c.jobTitle) subBits.push(c.jobTitle);
    if (c.company) subBits.push(c.company);
    if (subBits.length) main.appendChild(el('div', { class: 'contact-card__sub', text: subBits.join(' • ') }));
    else if (c.phones && c.phones.length) {
      main.appendChild(el('div', { class: 'contact-card__sub', text: Jalali.toPersianDigits(c.phones[0].value) }));
    }
    top.appendChild(main);

    var star = el('button', {
      class: 'contact-card__star' + (c.starred ? ' contact-card__star--on' : ''),
      title: c.starred ? 'حذف از علاقه‌مندی' : 'افزودن به علاقه‌مندی',
      html: '<svg class="icon" viewBox="0 0 24 24"><path d="M12 17.27 18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>'
    });
    star.dataset.action = 'star';
    top.appendChild(star);
    card.appendChild(top);

    // Tags
    if (c.tags && c.tags.length) {
      var tags = el('div', { class: 'contact-card__tags' });
      c.tags.slice(0, 4).forEach(function (tid) {
        var t = state.tagMap[tid];
        var name = t ? t.name : tid;
        var color = t ? t.color : '#6366f1';
        var chip = el('span', { class: 'chip', style: 'background:' + softBg(color) + '; color:' + color + ';' });
        chip.appendChild(el('span', { class: 'chip__dot', style: 'background:' + color }));
        chip.appendChild(document.createTextNode(name));
        tags.appendChild(chip);
      });
      if (c.tags.length > 4) {
        tags.appendChild(el('span', { class: 'chip', text: '+' + Jalali.toPersianDigits(c.tags.length - 4) }));
      }
      card.appendChild(tags);
    }

    return card;
  }

  function softBg(hex) {
    // produce a translucent background from a hex color
    var h = hex.replace('#', '');
    if (h.length === 3) h = h.split('').map(function (x) { return x + x; }).join('');
    var r = parseInt(h.slice(0, 2), 16);
    var g = parseInt(h.slice(2, 4), 16);
    var b = parseInt(h.slice(4, 6), 16);
    return 'rgba(' + r + ',' + g + ',' + b + ',0.12)';
  }

  // Grid click delegation (open detail, star toggle)
  function onGridClick(e) {
    var card = e.target.closest('.contact-card');
    if (!card) return;
    var id = card.dataset.id;
    if (e.target.closest('[data-action="star"]')) {
      e.stopPropagation();
      toggleStar(id);
      return;
    }
    openDetail(id);
  }

  function toggleStar(id) {
    var c = state.contacts.filter(function (x) { return x.id === id; })[0];
    if (!c) return;
    c.starred = !c.starred;
    DB.Contacts.save(c).then(function () { render(); renderSidebar(); });
  }

  /* =========================================================
     SIDEBAR
     ========================================================= */
  function renderSidebar() {
    // Counts
    var total = state.contacts.length;
    var starred = state.contacts.filter(function (c) { return c.starred; }).length;
    $('#count-all').textContent = Jalali.toPersianDigits(total);
    $('#count-starred').textContent = Jalali.toPersianDigits(starred);

    // Tags with counts
    var counts = {};
    state.contacts.forEach(function (c) {
      (c.tags || []).forEach(function (t) { counts[t] = (counts[t] || 0) + 1; });
    });

    // Make sure tagMap reflects what's in use
    Object.keys(counts).forEach(function (tid) {
      if (!state.tagMap[tid]) {
        var def = { id: tid, name: tid, color: DB.Tags.colorFor(tid) };
        state.tagMap[tid] = def;
      }
    });

    var tagBox = clear($('#sidebar-tags'));
    var tagIds = Object.keys(state.tagMap).sort(function (a, b) {
      return (counts[b] || 0) - (counts[a] || 0) || a.localeCompare(b, 'fa');
    });

    if (tagIds.length === 0) {
      tagBox.appendChild(el('div', { class: 'sidebar__tags-empty', text: 'هنوز برچسبی ساخته نشده' }));
      return;
    }
    tagIds.forEach(function (tid) {
      var t = state.tagMap[tid];
      var pill = el('button', { class: 'tag-pill' + (state.view === 'tag:' + tid ? ' tag-pill--active' : ''), dataset: { view: 'tag:' + tid } });
      pill.appendChild(el('span', { class: 'tag-pill__dot', style: 'background:' + t.color }));
      pill.appendChild(el('span', { class: 'tag-pill__name', text: t.name }));
      pill.appendChild(el('span', { class: 'tag-pill__count', text: Jalali.toPersianDigits(counts[tid] || 0) }));
      pill.addEventListener('click', function () { setView('tag:' + tid); });
      tagBox.appendChild(pill);
    });
  }

  /* =========================================================
     CONTACT FORM
     ========================================================= */
  function bindContactForm() {
    var form = $('#contact-form');
    form.addEventListener('submit', onSubmitContact);

    // Live avatar initials
    $('#f-firstName').addEventListener('input', updateFormAvatar);
    $('#f-lastName').addEventListener('input', updateFormAvatar);

    // Phones
    $('#add-phone').addEventListener('click', function () { addPhoneRow('mobile', ''); });
    // Emails
    $('#add-email').addEventListener('click', function () { addEmailRow(''); });

    // Tags input
    bindTagsInput();

    // Jalali date picker
    bindDatePicker();
  }

  function updateFormAvatar() {
    var f = $('#f-firstName').value;
    var l = $('#f-lastName').value;
    var av = $('#f-avatar');
    av.textContent = UI.initials(f, l);
    av.setAttribute('style', UI.avatarStyle(l || f || '؟'));
  }

  function openContactForm(id) {
    state.editingId = id || null;
    resetForm();

    if (id) {
      var c = findById(id);
      if (!c) return;
      $('#form-title').textContent = 'ویرایش مخاطب';
      $('#f-id').value = c.id;
      $('#f-firstName').value = c.firstName || '';
      $('#f-lastName').value = c.lastName || '';
      $('#f-company').value = c.company || '';
      $('#f-job').value = c.jobTitle || '';
      $('#f-address').value = c.address || '';
      $('#f-notes').value = c.notes || '';

      (c.phones || []).forEach(function (p) { addPhoneRow(p.type || 'mobile', p.value || ''); });
      if (!c.phones || !c.phones.length) addPhoneRow('mobile', '');
      (c.emails || []).forEach(function (e) { addEmailRow(e); });
      state.formTags = (c.tags || []).slice();
      if (c.birthday) {
        var parsed = Jalali.parse(c.birthday);
        if (parsed) { state.formBirthday = parsed; $('#f-birthday').value = Jalali.format(parsed); }
      }
    } else {
      $('#form-title').textContent = 'مخاطب جدید';
      addPhoneRow('mobile', '');
    }

    renderFormTags();
    updateFormAvatar();
    $('#f-birthday-clear').hidden = !state.formBirthday;
    UI.openModal('contact-modal');
  }

  function resetForm() {
    var form = $('#contact-form');
    form.reset();
    $('#f-id').value = '';
    clear($('#phones-wrap'));
    clear($('#emails-wrap'));
    state.formTags = [];
    state.formBirthday = null;
    $('#f-birthday').value = '';
    $('#f-birthday-clear').hidden = true;
    $$('.field__error').forEach(function (e) { e.textContent = ''; });
    $$('.field').forEach(function (f) { f.classList.remove('field--error'); });
  }

  var PHONE_TYPES = [
    ['mobile', 'موبایل'],
    ['home', 'منزل'],
    ['work', 'محل کار'],
    ['fax', 'فکس'],
    ['other', 'سایر']
  ];
  function addPhoneRow(type, value) {
    var wrap = $('#phones-wrap');
    var row = el('div', { class: 'repeat-row' });
    var sel = el('select');
    PHONE_TYPES.forEach(function (t) {
      var o = el('option', { value: t[0], text: t[1] });
      if (t[0] === type) o.selected = true;
      sel.appendChild(o);
    });
    row.appendChild(sel);
    var input = el('input', { type: 'tel', value: value, placeholder: '۰۹۱۲…' });
    input.dataset.field = 'phone';
    row.appendChild(input);
    var rm = el('button', { type: 'button', class: 'repeat-row__remove', title: 'حذف', html: '<svg class="icon" viewBox="0 0 24 24"><path d="M19 13H5v-2h14z"/></svg>' });
    rm.addEventListener('click', function () {
      // keep at least one row
      if (wrap.children.length > 1) row.remove();
      else input.value = '';
    });
    row.appendChild(rm);
    wrap.appendChild(row);
  }

  function addEmailRow(value) {
    var wrap = $('#emails-wrap');
    var row = el('div', { class: 'repeat-row' });
    var input = el('input', { type: 'email', value: value, placeholder: 'name@example.com', dir: 'ltr', style: 'text-align:right' });
    input.dataset.field = 'email';
    row.appendChild(input);
    var spacer = el('div', { style: 'width:92px;flex-shrink:0' });
    row.appendChild(spacer);
    var rm = el('button', { type: 'button', class: 'repeat-row__remove', title: 'حذف', html: '<svg class="icon" viewBox="0 0 24 24"><path d="M19 13H5v-2h14z"/></svg>' });
    rm.addEventListener('click', function () { row.remove(); });
    row.appendChild(rm);
    wrap.appendChild(row);
  }

  /* ---- Tags input behavior ---- */
  function bindTagsInput() {
    var field = $('#tags-field');
    var chipBox = $('#tags-chips');

    field.addEventListener('keydown', function (e) {
      if (e.key === 'Enter' || e.key === ',') {
        e.preventDefault();
        commitTag(field.value);
      } else if (e.key === 'Backspace' && !field.value && state.formTags.length) {
        state.formTags.pop();
        renderFormTags();
      }
    });
    field.addEventListener('blur', function () {
      if (field.value.trim()) commitTag(field.value);
    });
    chipBox.addEventListener('click', function (e) {
      var x = e.target.closest('.tag-chip__x');
      if (!x) return;
      var idx = +x.dataset.idx;
      state.formTags.splice(idx, 1);
      renderFormTags();
    });
    // Click anywhere in the chips area focuses the field
    $('#f-tags-input').addEventListener('click', function () { field.focus(); });
  }
  function commitTag(raw) {
    var name = raw.trim().replace(/,$/, '').trim();
    if (!name) { $('#tags-field').value = ''; return; }
    var id = name.toLowerCase();
    if (state.formTags.indexOf(id) === -1) state.formTags.push(id);
    $('#tags-field').value = '';
    renderFormTags();
    // ensure tag definition exists
    DB.Tags.ensure(name).then(function (t) {
      if (t) { state.tagMap[t.id] = t; }
    });
  }
  function renderFormTags() {
    var box = clear($('#tags-chips'));
    state.formTags.forEach(function (tid, idx) {
      var t = state.tagMap[tid] || { name: tid, color: DB.Tags.colorFor(tid) };
      var chip = el('span', { class: 'tag-chip', style: 'background:' + softBg(t.color) + '; color:' + t.color });
      chip.appendChild(document.createTextNode(t.name));
      chip.appendChild(el('button', { type: 'button', class: 'tag-chip__x', dataset: { idx: String(idx) }, title: 'حذف', html: '<svg class="icon" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>' }));
      box.appendChild(chip);
    });
  }

  /* ---- Submit ---- */
  function onSubmitContact(e) {
    e.preventDefault();
    // gather
    var lastName = $('#f-lastName').value.trim();
    var phones = [];
    $$('#phones-wrap input').forEach(function (inp) {
      var v = inp.value.trim();
      if (v) phones.push({ type: inp.parentElement.querySelector('select').value, value: v });
    });
    var emails = [];
    $$('#emails-wrap input').forEach(function (inp) {
      var v = inp.value.trim();
      if (v) emails.push(v);
    });

    // validation
    var errors = [];
    if (!lastName) errors.push({ field: 'f-lastName', msg: 'نام خانوادگی الزامی است.' });
    if (phones.length === 0) errors.push({ field: 'phones', msg: 'حداقل یک شماره تلفن الزامی است.' });
    emails.forEach(function (em) {
      if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(em)) errors.push({ field: 'emails', msg: 'ایمیل نامعتبر: ' + em });
    });
    if (errors.length) {
      $$('.field__error').forEach(function (e) { e.textContent = ''; });
      $$('.field').forEach(function (f) { f.classList.remove('field--error'); });
      errors.forEach(function (er) {
        var span = document.querySelector('.field__error[data-for="' + er.field + '"]');
        if (span) { span.textContent = er.msg; span.closest('.field').classList.add('field--error'); }
        else UI.toast(er.msg, 'error');
      });
      return;
    }

    var existing = state.editingId ? findById(state.editingId) : null;
    var contact = {
      id: existing ? existing.id : undefined,
      firstName: $('#f-firstName').value.trim(),
      lastName: lastName,
      company: $('#f-company').value.trim(),
      jobTitle: $('#f-job').value.trim(),
      phones: phones,
      emails: emails,
      address: $('#f-address').value.trim(),
      notes: $('#f-notes').value.trim(),
      tags: state.formTags.slice(),
      birthday: state.formBirthday ? Jalali.toLatinString(state.formBirthday) : '',
      starred: existing ? !!existing.starred : false,
      createdAt: existing ? existing.createdAt : undefined
    };

    DB.Contacts.save(contact).then(function (saved) {
      // update in-memory
      var idx = state.contacts.findIndex(function (c) { return c.id === saved.id; });
      if (idx >= 0) state.contacts[idx] = saved; else state.contacts.push(saved);
      return loadTags(); // refresh tagMap
    }).then(function () {
      UI.closeModal('contact-modal');
      renderSidebar();
      render();
      UI.toast(state.editingId ? 'مخاطب ویرایش شد' : 'مخاطب اضافه شد', 'success');
    }).catch(function (err) {
      console.error(err);
      UI.toast('خطا در ذخیره‌سازی', 'error');
    });
  }

  function findById(id) {
    return state.contacts.filter(function (c) { return c.id === id; })[0];
  }

  /* =========================================================
     DETAIL MODAL
     ========================================================= */
  function bindDetailModal() {
    $('#d-edit').addEventListener('click', function () {
      var id = $('#detail-modal').dataset.id;
      UI.closeModal('detail-modal');
      setTimeout(function () { openContactForm(id); }, 60);
    });
    $('#d-star').addEventListener('click', function () {
      var id = $('#detail-modal').dataset.id;
      toggleStar(id);
      var c = findById(id);
      $('#d-star').classList.toggle('starred', c && c.starred);
    });
    $('#d-delete').addEventListener('click', function () {
      var id = $('#detail-modal').dataset.id;
      var c = findById(id);
      if (!c) return;
      UI.confirm({
        title: 'حذف مخاطب؟',
        message: 'آیا «' + (c.fullName || 'این مخاطب') + '» حذف شود؟ این عمل قابل بازگشت نیست.',
        okText: 'حذف'
      }).then(function (ok) {
        if (!ok) return;
        DB.Contacts.remove(id).then(function () {
          state.contacts = state.contacts.filter(function (x) { return x.id !== id; });
          UI.closeModal('detail-modal');
          renderSidebar();
          render();
          UI.toast('مخاطب حذف شد', 'success');
        });
      });
    });
  }

  function openDetail(id) {
    var c = findById(id);
    if (!c) return;
    var modal = $('#detail-modal');
    modal.dataset.id = id;

    // Head
    var av = $('#d-avatar');
    av.textContent = UI.initials(c.firstName, c.lastName, c.fullName);
    av.setAttribute('style', UI.avatarStyle(c.lastName || c.firstName || c.id));
    $('#d-name').textContent = c.fullName || 'بدون نام';
    var jc = [];
    if (c.jobTitle) jc.push(c.jobTitle);
    if (c.company) jc.push(c.company);
    $('#d-jobcompany').textContent = jc.join(' • ');
    $('#d-star').classList.toggle('starred', !!c.starred);

    // Body
    var body = clear($('#detail-body'));
    if (c.phones && c.phones.length) {
      c.phones.forEach(function (p) {
        body.appendChild(detailRow('phone', phoneTypeLabel(p.type), p.value, true));
      });
    }
    if (c.emails && c.emails.length) {
      c.emails.forEach(function (em) {
        body.appendChild(detailRow('email', 'ایمیل', em, true, 'mailto:' + em));
      });
    }
    if (c.company) body.appendChild(detailRow('company', 'شرکت', c.company));
    if (c.jobTitle) body.appendChild(detailRow('job', 'سمت', c.jobTitle));
    if (c.address) body.appendChild(detailRow('address', 'آدرس', c.address));
    if (c.birthday) {
      var parsed = Jalali.parse(c.birthday);
      body.appendChild(detailRow('cake', 'تاریخ تولد', parsed ? Jalali.format(parsed, 'long') : c.birthday));
    }
    if (c.notes) body.appendChild(detailRow('notes', 'یادداشت', c.notes));
    if (c.tags && c.tags.length) {
      var row = el('div', { class: 'detail-row' });
      row.appendChild(iconBox('tag'));
      var bd = el('div', { class: 'detail-row__body' });
      bd.appendChild(el('div', { class: 'detail-row__label', text: 'برچسب‌ها' }));
      var val = el('div', { class: 'detail-row__value' });
      c.tags.forEach(function (tid) {
        var t = state.tagMap[tid] || { name: tid, color: DB.Tags.colorFor(tid) };
        var chip = el('span', { class: 'chip', style: 'background:' + softBg(t.color) + '; color:' + t.color });
        chip.appendChild(el('span', { class: 'chip__dot', style: 'background:' + t.color }));
        chip.appendChild(document.createTextNode(t.name));
        val.appendChild(chip);
      });
      bd.appendChild(val);
      row.appendChild(bd);
      body.appendChild(row);
    }

    // Meta
    var meta = el('div', { class: 'detail-meta' });
    if (c.createdAt) meta.appendChild(el('span', { text: 'ساخته شده: ' + Jalali.formatDate(c.createdAt, 'long') }));
    if (c.updatedAt) meta.appendChild(el('span', { text: 'ویرایش: ' + Jalali.formatDate(c.updatedAt, 'long') }));
    body.appendChild(meta);

    UI.openModal('detail-modal');
  }

  var ICON_PATHS = {
    phone: '<path d="M6.62 10.79a15.15 15.15 0 0 0 6.59 6.59l2.2-2.2a1 1 0 0 1 1.02-.24c1.12.37 2.33.57 3.57.57a1 1 0 0 1 1 1V20a1 1 0 0 1-1 1A17 17 0 0 1 3 4a1 1 0 0 1 1-1h3.5a1 1 0 0 1 1 1c0 1.25.2 2.45.57 3.57a1 1 0 0 1-.25 1.02l-2.2 2.2z"/>',
    email: '<path d="M20 4H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zm0 4-8 5-8-5V6l8 5 8-5v2z"/>',
    company: '<path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/>',
    job: '<path d="M20 6h-4V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v2H4a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2zM10 4h4v2h-4V4z"/>',
    address: '<path d="M12 2a7 7 0 0 0-7 7c0 5.25 7 13 7 13s7-7.75 7-13a7 7 0 0 0-7-7zm0 9.5A2.5 2.5 0 1 1 12 6.5a2.5 2.5 0 0 1 0 5z"/>',
    cake: '<path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99-1.07-1.07-1.06 1.07-1.06-1.07L12 15.99l-1.06-1.06-1.06 1.07-1.06-1.07L7.65 15.99 6.59 14.93c-.18.21-.34.43-.46.68L6 16v6h12v-6l-.13-.39c-.12-.25-.28-.48-.46-.69l-1.06 1.06zM12 8H6a2 2 0 0 0-2 2v3.59l1 .99 1.06-1.07L7.13 14.6 8.19 13.53l1.06 1.07L10.31 13.6 11.37 14.67l.63-.7.63.7 1.06-1.07 1.06 1.07 1.06-1.07 1.06 1.07 1-.99V10a2 2 0 0 0-2-2h-2z"/>',
    notes: '<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8l-6-6zm4 18H6V4h7v5h5v11z"/>',
    tag: '<path d="M21.41 11.58 12.41 2.58A2 2 0 0 0 11 2H4a2 2 0 0 0-2 2v7a2 2 0 0 0 .59 1.42l9 9a2 2 0 0 0 1.41.58 2 2 0 0 0 1.42-.59l7-7a2 2 0 0 0 0-2.83zM5.5 7A1.5 1.5 0 1 1 7 5.5 1.5 1.5 0 0 1 5.5 7z"/>'
  };
  function iconBox(name) {
    return el('div', { class: 'detail-row__icon', html: '<svg class="icon" viewBox="0 0 24 24">' + (ICON_PATHS[name] || ICON_PATHS.notes) + '</svg>' });
  }
  function detailRow(iconName, label, value, ltr, href) {
    var row = el('div', { class: 'detail-row' });
    row.appendChild(iconBox(iconName));
    var bd = el('div', { class: 'detail-row__body' });
    bd.appendChild(el('div', { class: 'detail-row__label', text: label }));
    var val = el('div', { class: 'detail-row__value' + (ltr ? ' dir-ltr' : ''), style: ltr ? 'direction:ltr' : '' });
    var content;
    if (href) content = el('a', { href: href, text: value });
    else content = document.createTextNode(value);
    val.appendChild(content);
    // copy button
    var copyBtn = el('button', { class: 'detail-row__copy', title: 'کپی', html: '<svg class="icon" viewBox="0 0 24 24"><path d="M16 1H4a2 2 0 0 0-2 2v14h2V3h12V1zm3 4H8a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h11a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2zm0 16H8V7h11v14z"/></svg>' });
    copyBtn.addEventListener('click', function () {
      UI.copyText(value).then(function () { UI.toast('کپی شد', 'success'); }).catch(function () { UI.toast('کپی ناموفق', 'error'); });
    });
    val.appendChild(copyBtn);
    bd.appendChild(val);
    row.appendChild(bd);
    return row;
  }
  function phoneTypeLabel(t) {
    var m = { mobile: 'موبایل', home: 'منزل', work: 'محل کار', fax: 'فکس', other: 'تلفن' };
    return m[t] || 'تلفن';
  }

  /* =========================================================
     JALALI DATE PICKER
     ========================================================= */
  var dpState = { view: null }; // current viewed {jy, jm}

  function bindDatePicker() {
    $('#f-birthday-btn').addEventListener('click', function (e) {
      e.stopPropagation();
      openDatePicker();
    });
    $('#f-birthday').addEventListener('click', openDatePicker);
    $('#f-birthday-clear').addEventListener('click', function () {
      state.formBirthday = null;
      $('#f-birthday').value = '';
      $('#f-birthday-clear').hidden = true;
    });

    // Prev/next/today/none
    $('.datepicker').addEventListener('click', function (e) {
      var btn = e.target.closest('[data-dp]');
      if (!btn) return;
      var act = btn.dataset.dp;
      if (act === 'prev') {
        dpState.view.jm--; if (dpState.view.jm < 1) { dpState.view.jm = 12; dpState.view.jy--; }
        renderDatePicker();
      } else if (act === 'next') {
        dpState.view.jm++; if (dpState.view.jm > 12) { dpState.view.jm = 1; dpState.view.jy++; }
        renderDatePicker();
      } else if (act === 'today') {
        var t = Jalali.today();
        state.formBirthday = t;
        $('#f-birthday').value = Jalali.format(t);
        $('#f-birthday-clear').hidden = false;
        closeDatePicker();
      } else if (act === 'none') {
        state.formBirthday = null;
        $('#f-birthday').value = '';
        $('#f-birthday-clear').hidden = true;
        closeDatePicker();
      }
    });

    // Day click
    $('#dp-grid').addEventListener('click', function (e) {
      var d = e.target.closest('.dp-day');
      if (!d || d.classList.contains('dp-day--disabled')) return;
      var jd = +d.dataset.day;
      var jy = dpState.view.jy, jm = dpState.view.jm;
      if (d.classList.contains('dp-day--other')) {
        // crossed into prev/next month
        if (jd > 15) { jm--; if (jm < 1) { jm = 12; jy--; } }
        else { jm++; if (jm > 12) { jm = 1; jy++; } }
      }
      state.formBirthday = { jy: jy, jm: jm, jd: jd };
      $('#f-birthday').value = Jalali.format(state.formBirthday);
      $('#f-birthday-clear').hidden = false;
      closeDatePicker();
    });

    // Close on outside click
    document.addEventListener('click', function (e) {
      var dp = $('#datepicker');
      if (dp.hidden) return;
      if (!dp.contains(e.target) && !e.target.closest('#f-birthday-btn') && !e.target.closest('#f-birthday')) {
        closeDatePicker();
      }
    });
  }

  function openDatePicker() {
    var start = state.formBirthday || Jalali.today();
    dpState.view = { jy: start.jy, jm: start.jm };
    renderDatePicker();
    var dp = $('#datepicker');
    dp.hidden = false;
    // position under the input
    var input = $('#f-birthday');
    var rect = input.getBoundingClientRect();
    // In RTL, anchor to right edge of input
    var top = rect.bottom + 6;
    var dpWidth = 296;
    var left = rect.right - dpWidth;
    if (left < 8) left = 8;
    if (top + 340 > window.innerHeight) top = rect.top - 346;
    dp.style.top = top + 'px';
    dp.style.left = left + 'px';
    dp.style.right = 'auto';
  }
  function closeDatePicker() { $('#datepicker').hidden = true; }

  function renderDatePicker() {
    var v = dpState.view;
    $('#dp-title').textContent = Jalali.MONTHS[v.jm - 1] + ' ' + Jalali.toPersianDigits(v.jy);

    // weekdays row (Sat..Fri)
    var wdBox = clear($('#dp-weekdays'));
    Jalali.WEEKDAY_ABBR.forEach(function (w) { wdBox.appendChild(el('span', { text: w })); });

    var grid = clear($('#dp-grid'));
    var daysInMonth = Jalali.daysInMonth(v.jy, v.jm);
    var firstWeekday = Jalali.weekdayOf(v.jy, v.jm, 1); // 0=Sat
    var prevMonthDays = (v.jm === 1) ? Jalali.daysInMonth(v.jy - 1, 12) : Jalali.daysInMonth(v.jy, v.jm - 1);

    var today = Jalali.today();
    var selected = state.formBirthday;

    for (var i = 0; i < firstWeekday; i++) {
      var dayNum = prevMonthDays - firstWeekday + i + 1;
      grid.appendChild(el('div', { class: 'dp-day dp-day--other', text: Jalali.toPersianDigits(dayNum), dataset: { day: String(dayNum) } }));
    }
    for (var d = 1; d <= daysInMonth; d++) {
      var classes = 'dp-day';
      if (selected && selected.jy === v.jy && selected.jm === v.jm && selected.jd === d) classes += ' dp-day--selected';
      if (today.jy === v.jy && today.jm === v.jm && today.jd === d) classes += ' dp-day--today';
      grid.appendChild(el('div', { class: classes, text: Jalali.toPersianDigits(d), dataset: { day: String(d) } }));
    }
    // trailing
    var totalCells = firstWeekday + daysInMonth;
    var trailing = (7 - (totalCells % 7)) % 7;
    for (var t = 1; t <= trailing; t++) {
      grid.appendChild(el('div', { class: 'dp-day dp-day--other', text: Jalali.toPersianDigits(t), dataset: { day: String(t) } }));
    }
  }

  /* =========================================================
     EXCEL IMPORT / EXPORT
     ========================================================= */
  var EXCEL_HEADERS = {
    firstName: 'نام',
    lastName: 'نام خانوادگی',
    company: 'شرکت',
    jobTitle: 'سمت',
    phones: 'تلفن‌ها',
    emails: 'ایمیل‌ها',
    tags: 'برچسب‌ها',
    address: 'آدرس',
    birthday: 'تاریخ تولد (شمسی)',
    notes: 'یادداشت',
    createdAt: 'تاریخ ایجاد',
    updatedAt: 'تاریخ ویرایش'
  };

  function exportExcel() {
    if (state.contacts.length === 0) { UI.toast('مخاطبی برای خروجی وجود ندارد', 'error'); return; }
    var rows = state.contacts.map(function (c) {
      return {
        'نام': c.firstName || '',
        'نام خانوادگی': c.lastName || '',
        'شرکت': c.company || '',
        'سمت': c.jobTitle || '',
        'تلفن‌ها': (c.phones || []).map(function (p) { return (PHONE_TYPE_LABELS_PERSIAN[p.type] || p.type) + ': ' + p.value; }).join(' | '),
        'ایمیل‌ها': (c.emails || []).join(' | '),
        'برچسب‌ها': (c.tags || []).map(function (t) { return state.tagMap[t] ? state.tagMap[t].name : t; }).join(' | '),
        'آدرس': c.address || '',
        'تاریخ تولد (شمسی)': c.birthday ? Jalali.format(Jalali.parse(c.birthday)) : '',
        'یادداشت': c.notes || '',
        'تاریخ ایجاد': Jalali.formatDate(c.createdAt, 'long'),
        'تاریخ ویرایش': Jalali.formatDate(c.updatedAt, 'long')
      };
    });
    var ws = XLSX.utils.json_to_sheet(rows);
    // RTL hint + column widths
    ws['!cols'] = [
      { wch: 12 }, { wch: 16 }, { wch: 18 }, { wch: 16 }, { wch: 28 },
      { wch: 28 }, { wch: 20 }, { wch: 26 }, { wch: 16 }, { wch: 26 }, { wch: 18 }, { wch: 18 }
    ];
    var wb = XLSX.utils.book_new();
    wb.Workbook = { Views: [{ RTL: true }] };
    XLSX.utils.book_append_sheet(wb, ws, 'مخاطبین');
    var stamp = Jalali.toLatinString(Jalali.today()).replace(/\//g, '-');
    XLSX.writeFile(wb, 'tamasa-contacts-' + stamp + '.xlsx');
    UI.toast(Jalali.toPersianDigits(state.contacts.length) + ' مخاطب خروجی گرفته شد', 'success');
  }
  var PHONE_TYPE_LABELS_PERSIAN = { mobile: 'موبایل', home: 'منزل', work: 'محل کار', fax: 'فکس', other: 'سایر' };
  var PHONE_TYPE_LABELS_REVERSE = {};
  Object.keys(PHONE_TYPE_LABELS_PERSIAN).forEach(function (k) { PHONE_TYPE_LABELS_REVERSE[PHONE_TYPE_LABELS_PERSIAN[k]] = k; });

  function handleImport(e) {
    var file = e.target.files[0];
    e.target.value = ''; // reset for re-import of same file
    if (!file) return;
    var reader = new FileReader();
    reader.onload = function (evt) {
      try {
        var data = new Uint8Array(evt.target.result);
        var wb = XLSX.read(data, { type: 'array' });
        var sheet = wb.Sheets[wb.SheetNames[0]];
        var json = XLSX.utils.sheet_to_json(sheet, { defval: '' });
        if (!json.length) { UI.toast('فایل خالی است', 'error'); return; }

        var imported = 0, skipped = 0;
        var pending = json.map(function (row) {
          var lastName = pick(row, ['نام خانوادگی', 'lastName', 'Last Name', 'فامیل']) || '';
          var firstName = pick(row, ['نام', 'firstName', 'First Name']) || '';
          var phonesRaw = pick(row, ['تلفن‌ها', 'phones', 'Phones', 'تلفن', 'موبایل', 'Mobile', 'Phone']);
          var phones = parsePhoneList(phonesRaw);
          if (!lastName || phones.length === 0) { skipped++; return null; }

          var emailsRaw = pick(row, ['ایمیل‌ها', 'emails', 'Emails', 'ایمیل', 'Email']) || '';
          var tagsRaw = pick(row, ['برچسب‌ها', 'tags', 'Tags', 'برچسب', 'گروه']) || '';

          return {
            firstName: firstName,
            lastName: lastName,
            company: pick(row, ['شرکت', 'company', 'Company']) || '',
            jobTitle: pick(row, ['سمت', 'jobTitle', 'Job Title', 'عنوان']) || '',
            phones: phones,
            emails: emailsRaw ? emailsRaw.split(/\||;|,|\n/).map(function (s) { return s.trim(); }).filter(Boolean) : [],
            tags: tagsRaw ? tagsRaw.split(/\||;|,/).map(function (s) { return s.trim().toLowerCase(); }).filter(Boolean) : [],
            address: pick(row, ['آدرس', 'address', 'Address']) || '',
            birthday: '',
            notes: pick(row, ['یادداشت', 'notes', 'Notes', 'توضیحات']) || '',
            starred: false
          };
        }).filter(Boolean);

        if (!pending.length) {
          UI.toast('هیچ رکورد معتبری برای ورود یافت نشد (نام خانوادگی و تلفن الزامی است)', 'error');
          return;
        }

        // ensure tags
        var tagEnsures = [];
        var seenTags = {};
        pending.forEach(function (c) {
          c.tags.forEach(function (t) {
            if (!seenTags[t]) { seenTags[t] = 1; tagEnsures.push(DB.Tags.ensure(t)); }
          });
        });
        Promise.all(tagEnsures).then(function (created) {
          created.forEach(function (t) { if (t) state.tagMap[t.id] = t; });
          return DB.Contacts.saveMany(pending);
        }).then(function () { return loadContacts(); })
          .then(function () {
            renderSidebar(); render();
            UI.toast(Jalali.toPersianDigits(pending.length) + ' مخاطب وارد شد' +
              (skipped ? ' (' + Jalali.toPersianDigits(skipped) + ' رد شد)' : ''), 'success');
          })
          .catch(function (err) { console.error(err); UI.toast('خطا در ورود اطلاعات', 'error'); });
      } catch (err) {
        console.error(err);
        UI.toast('فایل Excel قابل خواندن نیست', 'error');
      }
    };
    reader.readAsArrayBuffer(file);
  }

  function pick(row, keys) {
    for (var i = 0; i < keys.length; i++) {
      if (row[keys[i]] !== undefined && row[keys[i]] !== '' && row[keys[i]] !== null) return String(row[keys[i]]).trim();
    }
    return '';
  }
  function parsePhoneList(raw) {
    if (!raw) return [];
    var items = String(raw).split(/\||;|,|\n|\//);
    var out = [];
    items.forEach(function (s) {
      var v = s.trim();
      if (!v) return;
      var type = 'other';
      var m = v.match(/^(موبایل|منزل|محل کار|فکس|سایر|mobile|home|work|fax|other)[:：]\s*(.+)$/i);
      if (m) {
        type = PHONE_TYPE_LABELS_REVERSE[m[1]] || (m[1].toLowerCase());
        v = m[2].trim();
      }
      if (!v) return;
      // keep type mobile for typical mobile-looking numbers
      out.push({ type: type, value: v });
    });
    return out;
  }

  /* =========================================================
     BACKUP / RESTORE (JSON)
     ========================================================= */
  function backupJSON() {
    Promise.all([DB.Contacts.getAll(), DB.Tags.getAll(), DB.Settings.get('appMeta')]).then(function (results) {
      var backup = {
        app: 'tamasa',
        version: 1,
        exportedAt: new Date().toISOString(),
        contacts: results[0],
        tags: results[1]
      };
      var blob = new Blob([JSON.stringify(backup, null, 2)], { type: 'application/json' });
      var url = URL.createObjectURL(blob);
      var a = $('#export-link');
      a.href = url;
      var stamp = Jalali.toLatinString(Jalali.today()).replace(/\//g, '-');
      a.download = 'tamasa-backup-' + stamp + '.json';
      a.click();
      setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
      UI.toast('پشتیبان‌گیری انجام شد', 'success');
    });
  }

  function handleRestore(e) {
    var file = e.target.files[0];
    e.target.value = '';
    if (!file) return;
    var reader = new FileReader();
    reader.onload = function (evt) {
      var data;
      try { data = JSON.parse(evt.target.result); }
      catch (err) { console.error(err); UI.toast('فایل JSON قابل خواندن نیست', 'error'); return; }

      if (!data || data.app !== 'tamasa' || !Array.isArray(data.contacts)) {
        UI.toast('فایل پشتیبان معتبر نیست', 'error'); return;
      }
      UI.confirm({
        title: 'بازیابی از پشتیبان؟',
        message: 'این عمل تمام مخاطبین فعلی را با محتوای فایل پشتیبان جایگزین می‌کند. ادامه می‌دهید؟',
        okText: 'بازیابی'
      }).then(function (ok) {
        if (!ok) return;
        // 1) Re-create tag definitions (so colors/names survive), then
        // 2) replace the entire contacts dataset, then
        // 3) refresh in-memory state and re-render.
        var tagP = (Array.isArray(data.tags) && data.tags.length)
          ? Promise.all(data.tags.map(function (t) {
              return DB.Tags.ensure(t.name || t.id).then(function (saved) {
                if (saved && t.color) { saved.color = t.color; }
                return saved;
              });
            }))
          : Promise.resolve([]);
        tagP
          .then(function () { return DB.Contacts.replaceAll(data.contacts); })
          .then(function () { return loadTags(); })
          .then(function () { return loadContacts(); })
          .then(function () {
            renderSidebar(); render();
            UI.toast(Jalali.toPersianDigits(data.contacts.length) + ' مخاطب بازیابی شد', 'success');
          })
          .catch(function (err) { console.error(err); UI.toast('خطا در بازیابی', 'error'); });
      });
    };
    reader.readAsText(file, 'utf-8');
  }

})();
