/* Shared Supabase client + small helpers for the NRI Property Guard owner portal. */
(function () {
  var SUPABASE_URL = 'https://kwzjscbvyuotwhrcbxkw.supabase.co';
  var SUPABASE_ANON_KEY = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Imt3empzY2J2eXVvdHdocmNieGt3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODQ5NTE0NTQsImV4cCI6MjEwMDUyNzQ1NH0.2VazaDXTR95k5Gs4dGcwOI6a6rnY5-1aPumiyqO9BtE';

  window.sbClient = supabase.createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
    auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true }
  });

  window.NRIPG = {
    WHATSAPP_NUMBER: '919948039325',
    PHONE_DISPLAY: '+91 99480 39325',

    // ---- Pricing (confirmed with the account owner, 28 Aug 2026) ----
    // Replaces the old flat ₹3,000/property + ₹2,000/month Prime add-on
    // model with a visit-frequency structure: "Regular" is 1 inspection
    // visit/month, "Prime" is 2 visits/month (Prime keeps its existing
    // Emergency SOS perk too — that isn't changing). A customer with 1 or 2
    // properties pays the flat per-property rate below; a customer with
    // MORE THAN 2 properties (3+) gets the lower bulk per-property rate
    // instead — the account owner's instruction was specifically "more
    // than 2 properties", so exactly 2 still uses the standard rate, not
    // the bulk discount.
    PRICING: {
      standardRatePerProperty: { regular: 2000, prime: 3500 },
      bulkRatePerProperty: { regular: 1500, prime: 2500 },
      bulkThreshold: 2 // strictly more than this many properties triggers the bulk rate
    },
    // Actual monthly invoices are still created through whatever process
    // generates rows in the `invoices` table today (outside this codebase —
    // see the build summary); this calculator is what the website itself
    // uses to show a customer their current estimated monthly cost (Profile
    // tab), so it should be kept in sync with whatever that process charges.
    calcMonthlyAmount: function (propertyCount, tier) {
      var count = Math.max(0, Number(propertyCount) || 0);
      var t = (tier === 'prime') ? 'prime' : 'regular';
      var perProperty = count > this.PRICING.bulkThreshold
        ? this.PRICING.bulkRatePerProperty[t]
        : this.PRICING.standardRatePerProperty[t];
      return count * perProperty;
    },
    pricingRateDescription: function (propertyCount, tier) {
      var count = Math.max(0, Number(propertyCount) || 0);
      var t = (tier === 'prime') ? 'prime' : 'regular';
      var perProperty = count > this.PRICING.bulkThreshold
        ? this.PRICING.bulkRatePerProperty[t]
        : this.PRICING.standardRatePerProperty[t];
      var planLabel = t === 'prime' ? 'Prime — 2 visits/month' : 'Regular — 1 visit/month';
      return count + ' propert' + (count === 1 ? 'y' : 'ies') + ' × ' + this.fmtMoney(perProperty) + '/month (' + planLabel + ')';
    },

    // ---- UPI "Pay Now" ----
    // A lightweight UPI payment-intent link rather than a full payment
    // gateway integration (no Razorpay/Cashfree account or API keys exist
    // for this project yet — see the build summary's pending items). This
    // opens the customer's own UPI app (GPay/PhonePe/Paytm/...) with the
    // amount pre-filled; it works on a mobile browser but NOT on desktop
    // (there's no UPI app for a UPI link to hand off to), and — because
    // there's no payment gateway in the loop — it does not automatically
    // confirm payment back to this system. An invoice still needs to be
    // marked "Paid" by staff once payment is actually received.
    // TODO(account owner): replace UPI_VPA / UPI_PAYEE_NAME with your real
    // business UPI ID and registered name before this goes live.
    UPI_VPA: 'nripropertyguard@upi',
    UPI_PAYEE_NAME: 'NRI Property Guard',
    buildUpiLink: function (amount, note) {
      var params = 'pa=' + encodeURIComponent(this.UPI_VPA) +
        '&pn=' + encodeURIComponent(this.UPI_PAYEE_NAME) +
        '&am=' + encodeURIComponent(Number(amount).toFixed(2)) +
        '&cu=INR' +
        '&tn=' + encodeURIComponent(note || 'NRI Property Guard payment');
      return 'upi://pay?' + params;
    },
    isLikelyMobile: function () {
      return /Android|iPhone|iPad|iPod/i.test(navigator.userAgent || '');
    },

    fmtDate: function (iso) {
      if (!iso) return '—';
      try { return new Date(iso).toLocaleDateString('en-IN', { day: 'numeric', month: 'short', year: 'numeric' }); }
      catch (e) { return iso; }
    },
    fmtDateTime: function (iso) {
      if (!iso) return '—';
      try { return new Date(iso).toLocaleString('en-IN', { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }); }
      catch (e) { return iso; }
    },
    fmtMoney: function (n) {
      if (n === null || n === undefined) return '—';
      return '₹' + Number(n).toLocaleString('en-IN');
    },
    statusLabel: function (s) {
      var map = {
        draft: 'Draft', submitted: 'Submitted', admin_review: 'Admin Review',
        assigned_to_manager: 'Assigned to Manager', executive_assigned: 'Executive Assigned',
        visit_scheduled: 'Visit Scheduled', inspection_started: 'Inspection In Progress',
        inspection_completed: 'Inspection Completed', pending_manager_approval: 'Pending Manager Approval',
        approved: 'Approved', rejected: 'Rejected', revisit_requested: 'Re-visit Requested',
        scheduled: 'Scheduled', assigned: 'Executive Assigned', reached: 'Executive On-Site',
        in_progress: 'In Progress', pending_approval: 'Pending Manager Approval',
        completed: 'Completed', cancelled: 'Cancelled',
        open: 'Open', resolved: 'Resolved', closed: 'Closed',
        paid: 'Paid', due: 'Due', overdue: 'Overdue',
        healthy: 'Healthy', needsAttention: 'Needs Attention', underMaintenance: 'Under Maintenance', emergency: 'Emergency'
      };
      return map[s] || s || '—';
    },
    propertyTypeLabel: function (t) {
      var map = { villa: 'Villa / Independent House', apartment: 'Apartment', commercial: 'Commercial', agricultural: 'Agricultural Land', plot: 'Plot / Land', underConstruction: 'Under Construction' };
      return map[t] || t;
    },
    escapeHtml: function (s) {
      if (s === null || s === undefined) return '';
      return String(s).replace(/[&<>"']/g, function (c) {
        return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c];
      });
    },
    initials: function (name) {
      if (!name) return '?';
      var parts = name.trim().split(/\s+/);
      return ((parts[0] || '')[0] || '') + ((parts[1] || '')[0] || '');
    },
    toast: function (msg, type) {
      var el = document.getElementById('toast');
      if (!el) return;
      el.textContent = msg;
      el.className = 'toast show ' + (type || 'info');
      clearTimeout(window._toastT);
      window._toastT = setTimeout(function () { el.classList.remove('show'); }, 4200);
    },
    /* Phase 8: the on-media timestamp/GPS overlay this used to render (geoStamp())
       was removed at the user's explicit request — GPS and capture time are
       still recorded on every visit_photos/visit_videos row (mandatory, see
       executive-dashboard.js's uploadFiles()) and still power the tamper-evident
       audit trail and inspection report, they're just not drawn on top of the
       photo/video in any dashboard. */
    /* Calls fn on a fixed interval so every dashboard reflects backend changes
       without the user manually reloading, skipping ticks while the tab isn't
       in focus (document.hidden) so a backgrounded tab doesn't keep hammering
       the database. This is deliberately independent of the Realtime
       subscriptions some dashboards also use — Realtime only covers a subset
       of tables filtered to the signed-in user, so this is the backstop that
       makes every screen, on every role, eventually catch up regardless. */
    startAutoRefresh: function (fn, intervalMs) {
      var ms = intervalMs || 30000;
      return setInterval(function () {
        if (document.hidden) return;
        fn();
      }, ms);
    },
    /* rows: array of objects with matching keys. Generates a client-side CSV
       download — used by the Admin dashboard's analytics/reports export.
       No server round-trip and no data leaves the browser beyond the file save. */
    downloadCsv: function (filename, rows) {
      if (!rows || !rows.length) return;
      var cols = Object.keys(rows[0]);
      var esc = function (v) {
        if (v === null || v === undefined) return '';
        var s = String(v);
        return /[",\n]/.test(s) ? '"' + s.replace(/"/g, '""') + '"' : s;
      };
      var lines = [cols.join(',')].concat(rows.map(function (r) { return cols.map(function (c) { return esc(r[c]); }).join(','); }));
      var blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8;' });
      var url = URL.createObjectURL(blob);
      var a = document.createElement('a');
      a.href = url; a.download = filename;
      document.body.appendChild(a); a.click(); document.body.removeChild(a);
      setTimeout(function () { URL.revokeObjectURL(url); }, 1000);
    },
    /* ---- Lightbox maximize / fullscreen (shared by every dashboard's photo
       & video viewer) ----
       The lightbox itself already opens at a fixed, comfortable size with no
       internal scrolling (see .lightbox-modal in portal.css) — this just lets
       the viewer go bigger on request. Real Fullscreen API is tried first
       (with vendor-prefixed fallbacks for older Safari); if the browser
       blocks or lacks it — e.g. inside a sandboxed iframe — the CSS
       .is-maximized class expands the modal to nearly the full viewport
       instead, so "maximize" always does *something* rather than silently
       failing. */
    _fsEl: function () {
      return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement || null;
    },
    _requestFs: function (el) {
      var fn = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen;
      if (!fn) return Promise.reject(new Error('Fullscreen API unavailable'));
      var res = fn.call(el);
      return res && res.then ? res : Promise.resolve();
    },
    _exitFs: function () {
      var fn = document.exitFullscreen || document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen;
      if (!fn) return Promise.resolve();
      var res = fn.call(document);
      return res && res.then ? res : Promise.resolve();
    },
    toggleModalMaximize: function (el) {
      if (!el) return;
      var self = this;
      if (this._fsEl() === el) { this._exitFs(); return; }
      if (this._fsEl()) { this._exitFs(); }
      if (el.classList.contains('is-maximized')) { el.classList.remove('is-maximized'); return; }
      this._requestFs(el).catch(function () { el.classList.toggle('is-maximized'); });
    },
    resetModalMaximize: function (el) {
      if (!el) return;
      if (this._fsEl() === el) this._exitFs();
      el.classList.remove('is-maximized');
    }
  };
})();
