# -*- coding: utf-8 -*-
from dateutil.relativedelta import relativedelta

from odoo import api, exceptions, fields, models
from odoo.tools import float_utils as floatTool

class EstateProperty(models.Model):

    # ------------- Private attributes ------------------------- #

    _name = "estate.property"
    _description = "Properties for the Estate module"
    _order = "id desc"
    _check_company_auto = True

    _sql_constraints = [
        ('check_expected_price', 'CHECK (expected_price > 0)', 'Expected rice should be superior to 0'),
        ('check_selling_price', 'CHECK (selling_price >= 0)', 'Selling price cannot be negative'),
        ('unique_name', 'UNIQUE (name)', 'A property with this name aready exists. Name should be unique.'),
    ]

    # ------------- Fields ------------------------- #

    def _default_date_availability(self):
        return fields.Date.context_today(self) + relativedelta(months=3) 

    name = fields.Char(required=True)
    description = fields.Text()
    active = fields.Boolean(default=True)
    state = fields.Selection(selection=[('new','New'), ('offer_received', 'Offer Received'), ('offer_accepted', 'Offer Accepted'), ('sold', 'Sold'), ('cancelled', 'Cancelled')], required=True, copy=False, default='new')
    postcode = fields.Char()
    date_availability = fields.Date(copy=False, default=lambda self: self._default_date_availability())
    expected_price = fields.Float(required=True)
    selling_price = fields.Float(readonly=True, copy=False)
    bedrooms = fields.Integer(default=2)
    living_area = fields.Integer()
    facades = fields.Integer()
    garage = fields.Boolean()
    garden = fields.Boolean()
    garden_area = fields.Integer()
    garden_orientation = fields.Selection(selection=[('north', 'North'), ('south', 'South'), ('east', 'East'), ('west', 'West')])
    property_type_id = fields.Many2one("estate.property.type", "Property Type")
    salesman_id = fields.Many2one("res.users", string="Salesman", check_company=True)
    buyer_id = fields.Many2one("res.partner", string="Buyer", check_company=True)
    tag_ids = fields.Many2many("estate.property.tag", string="Tags")
    offer_ids = fields.One2many("estate.property.offer", "property_id", string="Offers")
    total_area = fields.Integer(compute="_get_total_area", readonly=True)
    best_price = fields.Float(compute="_compute_best_price")
    company_id = fields.Many2one('res.company', 'Company', required=True, default=lambda self: self.env.company)


    # ----------------- CRUD methods  --------------------------- #

    @api.ondelete(at_uninstall=False)
    def _unlink_if_new_cancelled(self):
        for record in self:
            if record.state not in ('new', 'cancelled'):
                raise exceptions.UserError("Cannot delete a property not new or cancelled")

    # ------------- Compute methods  ------------------------- #

    @api.depends('living_area', 'garden_area')
    def _get_total_area(self):
        for entry in self:
            entry.total_area = entry.living_area + entry.garden_area

    @api.depends('offer_ids.price')
    def _compute_best_price(self):
        for record in self:
            record.best_price = max(record.offer_ids.mapped('price')) if record.offer_ids else None

    # ------------- OnChange ------------------------- #

    @api.onchange('garden')
    def _onchange_garden(self):
        if self.garden:
            self.garden_area = 10
            self.garden_orientation = 'north'
        else:
            self.garden_area = None
            self.garden_orientation = None

    @api.onchange('date_availability')
    def _onchange_date_availability(self):
        if self.date_availability < fields.Date.today():
            return {'warning': {
                'title': ("Warning"),
                'message': ("The date is in the past.")}}

    # ------------- Constrains ------------------------- #

    @api.constrains('selling_price', 'expected_price')
    def _check_selling_price(self):
        for property in self:
            if (
                not floatTool.float_is_zero(property.selling_price, precision_rounding=0.01) 
                and floatTool.float_compare((property.expected_price * 0.9), property.selling_price, precision_rounding=0.01) > 0
            ):
                raise exceptions.ValidationError("Selling price can't be less than 90% of the expected price")

    # ------------- Actions ------------------------- #
            
    def action_sold(self):
        if self.exists():
            if self.state == 'cancelled':
                raise exceptions.UserError('A cancelled property cannot be sold')
            if "accepted" not in self.offer_ids.mapped("state"):
                raise exceptions.ValidationError('Cannot sell a property with no accepted offers')
            else:
                self.state = 'sold'
            return True
        else:
            raise exceptions.MissingError('Property not found')

    def action_cancel(self):
        if self.exists():
            if self.state == 'sold':
                raise exceptions.UserError('A sold property cannot be cancelled')
            else:
                self.state = 'cancelled'
            return True
        else:
            raise exceptions.MissingError('Property not found')