# Copyright 2026 Criptomart
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from datetime import date, timedelta

import odoo
from odoo.tests.common import TransactionCase


@odoo.tests.tagged("post_install", "-at_install")
class TestPosDashboardCooperative(TransactionCase):
    """Validate the extra dimensions added by pos_dashboard_cooperative on
    top of point_of_sale.report.pos.order:

      - time dimensions (date_day, hour_of_day, day_of_week)
      - product category hierarchy (categ_root_id, categ_parent_id)
      - cooperative member historic flag (is_member_at_date)

    These tests use a minimal hand-built pos.session to stay independent
    from any existing data in the database and from the heavy
    TestPoSCommon setup machinery, which requires a clean accounting
    setup.
    """

    @classmethod
    def setUpClass(cls):
        super().setUpClass()
        cls.company = cls.env.ref("base.main_company")

        # Two-level category hierarchy: family -> subfamily -> leaf
        cls.family_root = cls.env["product.category"].create(
            {"name": "DASHBOARD-FAMILY-ROOT"}
        )
        cls.subfamily = cls.env["product.category"].create(
            {"name": "DASHBOARD-SUBFAMILY", "parent_id": cls.family_root.id}
        )
        cls.categ_leaf = cls.env["product.category"].create(
            {"name": "DASHBOARD-LEAF", "parent_id": cls.subfamily.id}
        )

        # Product sold at the POS in every test.
        cls.product = cls.env["product.product"].create(
            {
                "name": "DASHBOARD-PRODUCT",
                "type": "consu",
                "available_in_pos": True,
                "list_price": 10.0,
                "standard_price": 6.0,
                "categ_id": cls.categ_leaf.id,
            }
        )

        # Share product needed by cooperator.share.line.
        cls.share_product = cls.env["product.product"].create(
            {
                "name": "DASHBOARD-SHARE",
                "is_share": True,
                "type": "service",
                "list_price": 25.0,
            }
        )

        # Two partners: one cooperative member (share dated in the past)
        # and one non-member.
        cls.member_partner = cls.env["res.partner"].create(
            {"name": "DASHBOARD-MEMBER"}
        )
        cls.non_member_partner = cls.env["res.partner"].create(
            {"name": "DASHBOARD-NON-MEMBER"}
        )
        cls.env["share.line"].create(
            {
                "partner_id": cls.member_partner.id,
                "share_product_id": cls.share_product.id,
                "share_number": 1,
                "share_unit_price": 25.0,
                "effective_date": date.today() - timedelta(days=365),
                "company_id": cls.company.id,
            }
        )

        # Reuse an existing POS config to avoid bootstrapping payment
        # methods and journals from scratch. Any installed config is
        # acceptable since we never go through the POS UI.
        cls.pos_config = cls.env["pos.config"].search(
            [("company_id", "=", cls.company.id)], limit=1
        )
        assert cls.pos_config, "A pos.config in the main company is required."
        if not cls.pos_config.current_session_id:
            cls.pos_config.open_ui()
        cls.pos_session = cls.pos_config.current_session_id

    # ------------------------------------------------------------------
    # Helpers
    # ------------------------------------------------------------------
    def _create_pos_order(self, partner):
        return self.env["pos.order"].create(
            {
                "session_id": self.pos_session.id,
                "partner_id": partner.id,
                "company_id": self.company.id,
                "lines": [
                    (
                        0,
                        0,
                        {
                            "name": "DASHBOARD-OL",
                            "product_id": self.product.id,
                            "price_unit": 10.0,
                            "discount": 0,
                            "qty": 1.0,
                            "price_subtotal": 10.0,
                            "price_subtotal_incl": 10.0,
                            "total_cost": 6.0,
                        },
                    )
                ],
                "amount_total": 10.0,
                "amount_tax": 0.0,
                "amount_paid": 0.0,
                "amount_return": 0.0,
            }
        )

    def _reports_for(self, partner):
        return (
            self.env["report.pos.order"]
            .sudo()
            .search(
                [
                    ("product_id", "=", self.product.id),
                    ("partner_id", "=", partner.id),
                ],
                order="id",
            )
        )

    # ------------------------------------------------------------------
    # Tests
    # ------------------------------------------------------------------
    def test_member_flag_for_member_partner(self):
        """Partner with a share line predating the order is flagged as
        member."""
        self._create_pos_order(self.member_partner)
        reports = self._reports_for(self.member_partner)
        self.assertTrue(reports)
        self.assertTrue(reports[0].is_member_at_date)

    def test_member_flag_for_non_member_partner(self):
        """Partner without any share line is not flagged as member."""
        self._create_pos_order(self.non_member_partner)
        reports = self._reports_for(self.non_member_partner)
        self.assertTrue(reports)
        self.assertFalse(reports[0].is_member_at_date)

    def test_member_flag_is_historic(self):
        """Share line dated AFTER the order date does not mark the partner
        as member for that order."""
        future_member = self.env["res.partner"].create(
            {"name": "DASHBOARD-FUTURE-MEMBER"}
        )
        self._create_pos_order(future_member)
        self.env["share.line"].create(
            {
                "partner_id": future_member.id,
                "share_product_id": self.share_product.id,
                "share_number": 1,
                "share_unit_price": 25.0,
                "effective_date": date.today() + timedelta(days=30),
                "company_id": self.company.id,
            }
        )
        reports = self._reports_for(future_member)
        self.assertTrue(reports)
        self.assertFalse(
            reports[0].is_member_at_date,
            "Member flag must reflect the situation at order date.",
        )

    def test_category_hierarchy_is_resolved(self):
        """categ_root_id and categ_parent_id reflect the product category
        ancestors derived from parent_path."""
        self._create_pos_order(self.member_partner)
        reports = self._reports_for(self.member_partner)
        self.assertTrue(reports)
        report = reports[0]
        self.assertEqual(report.categ_root_id, self.family_root)
        self.assertEqual(report.categ_parent_id, self.subfamily)

    def test_time_dimensions_are_populated(self):
        """date_day matches order date; hour_of_day / day_of_week are in
        valid ranges."""
        self._create_pos_order(self.member_partner)
        reports = self._reports_for(self.member_partner)
        self.assertTrue(reports)
        report = reports[0]
        self.assertIsNotNone(report.date_day)
        self.assertGreaterEqual(report.hour_of_day, 0)
        self.assertLess(report.hour_of_day, 24)
        self.assertGreaterEqual(report.day_of_week, 1)
        self.assertLessEqual(report.day_of_week, 7)

    def test_read_group_by_member_flag(self):
        """Aggregations grouped by the member flag return one row per
        member status when both kinds of partners have purchased."""
        self._create_pos_order(self.member_partner)
        self._create_pos_order(self.non_member_partner)
        results = self.env["report.pos.order"].read_group(
            [("product_id", "=", self.product.id)],
            ["price_total", "is_member_at_date"],
            ["is_member_at_date"],
        )
        statuses = {r["is_member_at_date"] for r in results}
        self.assertIn(True, statuses)
        self.assertIn(False, statuses)
