# © 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from datetime import date

from odoo import fields, models


class ScopCotisation(models.AbstractModel):
    _name = "scop.cotisation"
    _description = "Base des cotisations"

    year = fields.Selection(
        [
            (str(year), str(year))
            for year in range(
                fields.Datetime.now().year - 1, fields.Datetime.now().year + 2
            )
        ],
        string="Année de cotisation",
        required=True,
    )
    company_id = fields.Many2one(
        comodel_name="res.company",
        string="Company",
        change_default=True,
        required=True,
        readonly=True,
        default=lambda self: self.env.company,
    )

    company_currency_id = fields.Many2one(
        comodel_name="res.currency",
        related="company_id.currency_id",
        string="Company Currency",
        readonly=True,
    )
    date_cotisation = fields.Date(
        string="Date calcul cotisation",
        help="Date de calcul qui apparaitra sur le bordereau de cotisation",
    )

    member_count = fields.Integer(
        "Adhérents renouvelés", compute="_compute_member_count"
    )
    new_member_count = fields.Integer(
        "Nouveaux adhérents", compute="_compute_new_member_count"
    )
    invoiced_member_count = fields.Integer(
        "Cotisations créées", compute="_compute_invoiced_member_count"
    )
    trimester_1 = fields.Date("1er Trimestre")
    trimester_2 = fields.Date("2ème Trimestre")
    trimester_3 = fields.Date("3ème Trimestre")
    trimester_4 = fields.Date("4ème Trimestre")

    # ------------------------------------------------------
    # Compute fields
    # ------------------------------------------------------
    def _compute_member_count(self):
        for cotiz in self:
            cotiz.member_count = len(cotiz.get_members())

    def _compute_new_member_count(self):
        for cotiz in self:
            cotiz.new_member_count = len(cotiz.get_new_members())

    def _compute_invoiced_member_count(self):
        for cotiz in self:
            cotiz.invoiced_member_count = len(cotiz.invoice_ids.mapped("partner_id"))

    # ------------------------------------------------------
    # Global functions
    # ------------------------------------------------------
    def get_members(self):
        self.ensure_one()
        members = (
            self.env["scop.membership.period"]
            .search(
                [
                    (
                        "type_id",
                        "=",
                        self.env.ref("cgscop_partner.membership_type_1").id,
                    ),
                    ("start", "<", date(int(self.year), 1, 1)),
                    ("end", "=", None),
                ]
            )
            .mapped("partner_id")
        )
        return members

    def get_new_members(self, limit_start_date=None):
        if not limit_start_date:
            limit_start_date = date(int(self.year), 12, 31)
        self.ensure_one()
        members = (
            self.env["scop.membership.period"]
            .search(
                [
                    (
                        "type_id",
                        "=",
                        self.env.ref("cgscop_partner.membership_type_1").id,
                    ),
                    ("start", ">=", date(int(self.year), 1, 1)),
                    ("start", "<=", limit_start_date),
                    "|",
                    ("end", "=", None),
                    ("end", ">", date(int(self.year), 1, 1)),
                ]
            )
            .mapped("partner_id")
        )
        return members

    def round_to_closest_multiple(self, float_to_round, multiple):
        """
        :param float_to_round:
        :param multiple:
        :return: closest_multiple
        """
        small_multiple = (float_to_round // multiple) * multiple
        large_multiple = small_multiple + multiple

        # Return the closest of two
        if abs(float_to_round - small_multiple) < abs(float_to_round - large_multiple):
            return small_multiple
        else:
            return large_multiple