"""Affiliate-side fields on res.partner.

Three roles:
* ``affiliate_referrer_config_id``: stamped on a *recruiter* partner at
  signup-time when the affiliate cookie/session is set. Persists the
  first-touch attribution beyond the session, so the recruiter can later
  publish jobs and still credit the affiliate.
* ``affiliate_commission_pct`` / ``affiliate_withdraw_limit``: per-affiliate
  defaults (V9 parity: affiliate.py:179, 183).
* ``affiliate_current_amount`` / ``_withdraw_amount`` / ``_paid_amount`` /
  ``affiliate_payable``: computed balances surfaced in the portal.
"""

from odoo import api, fields, models


class ResPartner(models.Model):
    _inherit = "res.partner"

    # ---- commission / widget config One2manys --------------------------
    commission_ids = fields.One2many(
        comodel_name="job.partner.commission",
        inverse_name="partner_id",
        string="Transactions",
    )
    affiliate_widget_config_ids = fields.One2many(
        comodel_name="affiliate.widget.config",
        inverse_name="partner_id",
        string="Widget Configurations",
    )

    # ---- attribution (set on recruiters at signup) -------------------
    affiliate_referrer_config_id = fields.Many2one(
        comodel_name="affiliate.widget.config",
        string="Affiliate Referrer",
        ondelete="set null",
        index=True,
        help="The widget config that referred this partner. Set at signup "
             "from the visitor's ?ref= / kj_aff cookie and used to credit "
             "commissions on later job publishes.",
    )

    # ---- per-affiliate config (only meaningful for role=affiliate) ---
    affiliate_commission_pct = fields.Integer(
        string="Commission %",
        default=100,
        help="Default commission percentage applied when this partner is "
             "the affiliate referrer on an auto-created commission.",
    )
    affiliate_withdraw_limit = fields.Monetary(
        string="Minimum Withdrawal",
        currency_field="affiliate_currency_id",
        default=lambda s: s._default_withdraw_limit(),
        help="Affiliate must have at least this much in available "
             "commissions before requesting a payout.",
    )
    affiliate_currency_id = fields.Many2one(
        comodel_name="res.currency",
        compute="_compute_affiliate_currency",
        help="Reporting currency for affiliate balances (company default).",
    )

    # ---- portal-facing balances --------------------------------------
    affiliate_current_amount = fields.Monetary(
        string="Available Commissions",
        compute="_compute_affiliate_balances",
        currency_field="affiliate_currency_id",
    )
    affiliate_withdraw_amount = fields.Monetary(
        string="Pending Payouts",
        compute="_compute_affiliate_balances",
        currency_field="affiliate_currency_id",
    )
    affiliate_paid_amount = fields.Monetary(
        string="Paid Out",
        compute="_compute_affiliate_balances",
        currency_field="affiliate_currency_id",
    )
    affiliate_payable = fields.Boolean(
        string="Eligible for Payout",
        compute="_compute_affiliate_balances",
        help="True when available commissions >= minimum withdrawal.",
    )

    # ------------------------------------------------------------------
    @api.model
    def _default_withdraw_limit(self):
        try:
            return float(self.env["ir.config_parameter"].sudo().get_param(
                "kj_affiliate.withdraw_limit_default", "0",
            ))
        except (TypeError, ValueError):
            return 0.0

    def _compute_affiliate_currency(self):
        ccy = self.env.company.currency_id
        for rec in self:
            rec.affiliate_currency_id = ccy

    def _compute_affiliate_balances(self):
        """Sum the partner's commission ledger.

        ``current = completed commissions − completed payouts − pending payouts``
        — matches V9 ``current_amount`` (affiliate.py:224-229).
        """
        Commission = self.env["job.partner.commission"].sudo()
        for rec in self:
            if rec.role_user_type != "affiliate":
                rec.affiliate_current_amount = 0.0
                rec.affiliate_withdraw_amount = 0.0
                rec.affiliate_paid_amount = 0.0
                rec.affiliate_payable = False
                continue
            rows = Commission.search([("partner_id", "=", rec.id)])
            done_comm = sum(
                r.commission_amount for r in rows
                if r.transaction_type == "commission" and r.state == "completed"
            )
            done_pay = sum(
                r.commission_amount for r in rows
                if r.transaction_type == "payout" and r.state == "completed"
            )
            pending_pay = sum(
                r.commission_amount for r in rows
                if r.transaction_type == "payout" and r.state == "pending"
            )
            rec.affiliate_paid_amount = done_pay
            rec.affiliate_withdraw_amount = pending_pay
            rec.affiliate_current_amount = done_comm - done_pay - pending_pay
            rec.affiliate_payable = (
                rec.affiliate_current_amount >= (rec.affiliate_withdraw_limit or 0.0)
                and rec.affiliate_current_amount > 0
            )

    # ------------------------------------------------------------------
    # Monthly summary cron (V9: affiliate_partners.transactions_notification)
    # ------------------------------------------------------------------
    @api.model
    def _kj_send_affiliate_monthly_summary(self):
        """For each active affiliate with ≥1 commission in the previous
        calendar month, render and send the monthly summary email.

        Re-anchored to res.partner (one mail per affiliate) — the body
        queries the partner's commissions directly.
        """
        from datetime import date, timedelta
        today = date.today()
        first_of_this_month = today.replace(day=1)
        last_of_prev = first_of_this_month - timedelta(days=1)
        first_of_prev = last_of_prev.replace(day=1)
        affiliates = self.sudo().search([
            ("role_user_type", "=", "affiliate"),
            ("active", "=", True),
            ("email", "!=", False),
        ])
        Commission = self.env["job.partner.commission"].sudo()
        template = self.env.ref(
            "kj_affiliate_widget.email_template_affiliate_monthly_summary",
            raise_if_not_found=False,
        )
        if not template:
            return
        for partner in affiliates:
            has_activity = Commission.search_count([
                ("partner_id", "=", partner.id),
                ("create_date", ">=", first_of_prev),
                ("create_date", "<", first_of_this_month),
            ])
            if not has_activity:
                continue
            template.send_mail(partner.id, force_send=False)
