/**
 * 交易日历组件:内照明心档案 + 三所统计分析共用.
 */
(function (global) {
  "use strict";

  var WEEKDAYS = ["日", "一", "二", "三", "四", "五", "六"];

  function esc(s) {
    return String(s == null ? "" : s)
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;");
  }

  function monthLabel(y, m) {
    return y + "年" + m + "月";
  }

  function formatCalPnl(pnl) {
    var n = Number(pnl);
    if (!Number.isFinite(n)) n = 0;
    return (n >= 0 ? "+" : "") + n.toFixed(1) + "U";
  }

  function dayHasTrade(info) {
    if (!info) return false;
    var cnt = Number(info.open_count);
    if (Number.isFinite(cnt) && cnt > 0) return true;
    var pnl = Number(info.pnl_total);
    return Number.isFinite(pnl) && Math.abs(pnl) > 0.0001;
  }

  function dayOpenCount(info) {
    var cnt = Number(info && info.open_count);
    return Number.isFinite(cnt) && cnt > 0 ? cnt : 0;
  }

  function dayPnl(info) {
    return Number(info && info.pnl_total) || 0;
  }

  function TradeStatsCalendar(config) {
    this.gridEl = config.gridEl;
    this.titleEl = config.titleEl;
    this.prevBtn = config.prevBtn || null;
    this.nextBtn = config.nextBtn || null;
    this.apiUrl = config.apiUrl || "/api/stats/calendar";
    this.buildQuery =
      config.buildQuery ||
      function (year, month) {
        var q = new URLSearchParams();
        q.set("year", String(year));
        q.set("month", String(month));
        return q;
      };
    this.parseResponse =
      config.parseResponse ||
      function (data) {
        if (data && data.ok === false) return {};
        return (data && data.days) || {};
      };
    this.fetchFn = config.fetchFn || null;
    this.showSick = config.showSick !== false;
    this.selectedDay = config.selectedDay || "";
    this.onDayClick = config.onDayClick || null;
    this.onMonthChange = config.onMonthChange || null;
    this.year = config.year || 0;
    this.month = config.month || 0;
    this.days = {};
    this.monthPnlTotal = 0;
    this.monthOpenCount = 0;
    this._navBound = false;
    this._bindNav();
  }

  TradeStatsCalendar.prototype.ensureMonth = function (ref) {
    if (this.year > 0 && this.month > 0) return;
    var d;
    if (ref instanceof Date) d = ref;
    else if (typeof ref === "string" && ref.length >= 7) {
      var p = ref.slice(0, 10).split("-");
      this.year = parseInt(p[0], 10) || new Date().getFullYear();
      this.month = parseInt(p[1], 10) || new Date().getMonth() + 1;
      return;
    } else d = new Date();
    this.year = d.getFullYear();
    this.month = d.getMonth() + 1;
  };

  TradeStatsCalendar.prototype.applyPayload = function (data) {
    if (!data) return;
    var y = Number(data.year);
    var m = Number(data.month);
    if (Number.isFinite(y) && y > 0) this.year = y;
    if (Number.isFinite(m) && m > 0) this.month = m;
    this.days = this.parseResponse(data) || {};
    this.monthPnlTotal = Number(data.month_pnl_total) || 0;
    this.monthOpenCount = Number(data.month_open_count) || 0;
    if (!this.monthOpenCount) {
      var self = this;
      Object.keys(this.days).forEach(function (k) {
        if (dayHasTrade(self.days[k])) {
          self.monthOpenCount += dayOpenCount(self.days[k]);
          self.monthPnlTotal += dayPnl(self.days[k]);
        }
      });
      this.monthPnlTotal = Math.round(this.monthPnlTotal * 10000) / 10000;
    }
  };

  function readStatsCalendarBootstrap() {
    var el = document.getElementById("stats-calendar-bootstrap");
    if (!el || !el.textContent) return null;
    try {
      return JSON.parse(el.textContent);
    } catch (e) {
      console.warn("[trade calendar] bootstrap parse", e);
      return null;
    }
  }

  TradeStatsCalendar.prototype.setSelectedDay = function (day) {
    this.selectedDay = day || "";
    this.render();
  };

  TradeStatsCalendar.prototype.render = function () {
    if (!this.gridEl || !this.titleEl) return;
    if (this.year <= 0 || this.month <= 0) this.ensureMonth(new Date());
    var title = monthLabel(this.year, this.month);
    if (this.monthOpenCount > 0) {
      title +=
        " · " + formatCalPnl(this.monthPnlTotal) + " · " + this.monthOpenCount + "笔";
    }
    this.titleEl.textContent = title;
    var first = new Date(this.year, this.month - 1, 1);
    var lastDay = new Date(this.year, this.month, 0).getDate();
    var startWd = first.getDay();
    var html =
      '<div class="trade-cal-weekdays">' +
      WEEKDAYS.map(function (w) {
        return '<span class="trade-cal-wd">' + w + "</span>";
      }).join("") +
      '</div><div class="trade-cal-grid">';
    var i;
    for (i = 0; i < startWd; i++) {
      html += '<span class="trade-cal-cell trade-cal-pad"></span>';
    }
    for (var d = 1; d <= lastDay; d++) {
      var dayStr =
        this.year +
        "-" +
        String(this.month).padStart(2, "0") +
        "-" +
        String(d).padStart(2, "0");
      var info = this.days[dayStr];
      var hasTrade = dayHasTrade(info);
      var sick = this.showSick && info && info.has_sick;
      var pnl = hasTrade ? dayPnl(info) : null;
      var cnt = hasTrade ? dayOpenCount(info) : 0;
      var cls =
        "trade-cal-cell" +
        (hasTrade ? " has-trade" : "") +
        (sick ? " is-sick-day" : "") +
        (this.selectedDay === dayStr ? " is-selected" : "") +
        (pnl != null && pnl > 0.0001
          ? " pnl-pos"
          : pnl != null && pnl < -0.0001
            ? " pnl-neg"
            : "");
      var body = '<span class="trade-cal-day-num">' + d + "</span>";
      if (hasTrade) {
        body +=
          '<span class="trade-cal-pnl">' +
          esc(formatCalPnl(pnl)) +
          "</span>" +
          '<span class="trade-cal-cnt">' +
          cnt +
          "笔</span>";
        if (sick) body += '<span class="trade-cal-sick-tag">犯病</span>';
      }
      html +=
        '<button type="button" class="' +
        cls +
        '" data-day="' +
        dayStr +
        '" data-sick="' +
        (sick ? "1" : "0") +
        '"' +
        (hasTrade ? "" : " disabled") +
        ">" +
        body +
        "</button>";
    }
    html += "</div>";
    this.gridEl.innerHTML = html;
    var self = this;
    this.gridEl.querySelectorAll(".trade-cal-cell[data-day]").forEach(function (btn) {
      btn.addEventListener("click", function () {
        var day = btn.getAttribute("data-day");
        if (!day || !self.onDayClick) return;
        self.selectedDay = day;
        self.render();
        self.onDayClick(day, btn.getAttribute("data-sick") === "1", self.days[day] || null);
      });
    });
  };

  TradeStatsCalendar.prototype.load = async function () {
    this.ensureMonth(new Date());
    this.render();
    var q = this.buildQuery(this.year, this.month);
    if (!q.has("year")) q.set("year", String(this.year));
    if (!q.has("month")) q.set("month", String(this.month));
    try {
      var data;
      if (this.fetchFn) {
        data = await this.fetchFn(q);
      } else {
        var resp = await fetch(this.apiUrl + "?" + q.toString(), {
          credentials: "same-origin",
        });
        if (!resp.ok) {
          console.warn("[trade calendar] api", resp.status);
          this.render();
          return;
        }
        data = await resp.json();
      }
      this.applyPayload(data);
      this.render();
      if (this.onMonthChange) this.onMonthChange(this.year, this.month, this.days);
    } catch (e) {
      console.warn("[trade calendar]", e);
      this.render();
    }
  };

  TradeStatsCalendar.prototype.shiftMonth = function (delta) {
    this.ensureMonth(new Date());
    this.month += delta;
    if (this.month > 12) {
      this.month = 1;
      this.year += 1;
    } else if (this.month < 1) {
      this.month = 12;
      this.year -= 1;
    }
    void this.load();
  };

  TradeStatsCalendar.prototype._bindNav = function () {
    if (this._navBound) return;
    var self = this;
    if (this.prevBtn) {
      this.prevBtn.addEventListener("click", function () {
        self.shiftMonth(-1);
      });
    }
    if (this.nextBtn) {
      this.nextBtn.addEventListener("click", function () {
        self.shiftMonth(1);
      });
    }
    this._navBound = true;
  };

  global.TradeStatsCalendar = TradeStatsCalendar;

  global.statsCalendarWidget = null;

  global.initInstanceStatsCalendar = function () {
    var grid = document.getElementById("stats-calendar");
    if (!grid || !global.TradeStatsCalendar) return null;
    var bootstrap = readStatsCalendarBootstrap();
    if (
      global.statsCalendarWidget &&
      global.statsCalendarWidget.gridEl === grid
    ) {
      if (bootstrap) global.statsCalendarWidget.applyPayload(bootstrap);
      global.statsCalendarWidget.render();
      void global.statsCalendarWidget.load();
      return global.statsCalendarWidget;
    }
    global.statsCalendarWidget = new TradeStatsCalendar({
      gridEl: grid,
      titleEl: document.getElementById("stats-cal-title"),
      prevBtn: document.getElementById("stats-cal-prev"),
      nextBtn: document.getElementById("stats-cal-next"),
      apiUrl: "/api/stats/calendar",
      showSick: false,
      buildQuery: function (year, month) {
        var q = new URLSearchParams();
        q.set("year", String(year));
        q.set("month", String(month));
        var sel = document.getElementById("stats-segment-select");
        if (sel) q.set("segment", sel.value || "all");
        return q;
      },
      parseResponse: function (data) {
        if (data && data.ok === false) return {};
        return (data && data.days) || {};
      },
    });
    if (bootstrap) global.statsCalendarWidget.applyPayload(bootstrap);
    global.statsCalendarWidget.render();
    void global.statsCalendarWidget.load();
    return global.statsCalendarWidget;
  };

  global.initStatsCalendarWidget = global.initInstanceStatsCalendar;
})(window);
