from odoo import models, fields, api
from datetime import date


class ProductTemplate(models.Model):
    _inherit = "product.template"

    po_min_suggest_if_forecast_le_zero = fields.Boolean(
        string="Suggest minimum purchase when forecast <= 0",
        help="If enabled, the purchase recommendation wizard will always propose at least 1 unit (or 1 full package when ordering by packages) when the forecasted stock is less or equal to 0.",
    )

    stock_out_period_ids = fields.One2many(
        "product.stock.out.period",
        "product_tmpl_id",
        string="Stock-out Periods",
        help="Historical periods where this product had zero stock (qty_available <= 0).",
    )

    def cron_update_stock_out_periods(self):
        """Scheduled every night: detect products currently without stock and
        update (or create) an open stock-out period. While a period is open:
          - end_date is kept updated each day with today's date
          - days_out reflects (end_date - start_date).days
        When stock returns the period is marked closed (is_open=False) but end_date
        keeps the last day without stock (previous day if we consider stock restored today).
        """
        # Consider only storable products
        products = self.search([("type", "=", "product")])
        today = date.today()
        # Prefetch qty_available efficiently (framework batches reads)
        for product in products:
            qty = product.qty_available
            open_period = product.stock_out_period_ids.filtered(lambda p: p.is_open)[:1]
            if qty <= 0:
                if open_period:
                    # Refresh end_date to today (still open)
                    if open_period.end_date != today:
                        open_period.end_date = today
                        open_period._compute_days_out()
                else:
                    self.env["product.stock.out.period"].create(
                        {
                            "product_tmpl_id": product.id,
                            "start_date": today,
                            "end_date": today,
                            "is_open": True,
                        }
                    )
            else:
                if open_period:
                    # Close period: stock restored today -> last day without stock was yesterday
                    # We set end_date to max(start_date, today - 1) to avoid negative spans.
                    from datetime import timedelta

                    closed_end = max(open_period.start_date, today - timedelta(days=1))
                    if open_period.end_date != closed_end:
                        open_period.end_date = closed_end
                    open_period.is_open = False
                    open_period._compute_days_out()


class ProductStockOutPeriod(models.Model):
    _name = "product.stock.out.period"
    _description = "Product Stock-out Period"
    _order = "start_date desc"

    product_tmpl_id = fields.Many2one(
        "product.template",
        required=True,
        ondelete="cascade",
        index=True,
        string="Product Template",
        help="Product template this stock-out period belongs to.",
    )
    start_date = fields.Date(
        required=True,
        index=True,
        string="Start Date",
        help="First calendar day when the product had zero stock in this period.",
    )
    end_date = fields.Date(
        index=True,
        string="End Date",
        help="Last calendar day (inclusive) the product remained without stock in this period.",
    )
    is_open = fields.Boolean(
        string="Open",
        default=False,
        index=True,
        help="Indicates the period is still ongoing (stock not yet restored).",
    )
    days_out = fields.Integer(
        string="Days without Stock",
        compute="_compute_days_out",
        store=True,
        help="Total number of calendar days (inclusive) without stock for this period.",
    )

    @api.depends("start_date", "end_date", "is_open")
    def _compute_days_out(self):
        for rec in self:
            if rec.start_date and rec.end_date:
                # Inclusive count of days (both start and end)
                rec.days_out = (rec.end_date - rec.start_date).days + 1
            else:
                rec.days_out = 0
