# -*- coding: utf-8 -*-

from datetime import date

from odoo import api, fields, models, _
from odoo.exceptions import UserError


class HrHolidaysPublic(models.Model):
    _name = 'hr.holidays.public'
    _description = 'Public Holidays'
    _rec_name = 'year'
    _order = "year"

    display_name = fields.Char("Name", compute="_compute_display_name", readonly=True, store=True, )
    year = fields.Integer("Calendar Year", required=True, default=date.today().year)
    line_ids = fields.One2many('hr.holidays.public.line', 'year_id', 'Holiday Dates')
    country_id = fields.Many2one('res.country', 'Country')

    @api.constrains('year', 'country_id')
    def _check_year(self):
        for line in self:
            line._check_year_one()

    def _check_year_one(self):
        if self.country_id:
            domain = [('year', '=', self.year),
                      ('country_id', '=', self.country_id.id),
                      ('id', '!=', self.id)]
        else:
            domain = [('year', '=', self.year),
                      ('country_id', '=', False),
                      ('id', '!=', self.id)]
        if self.search_count(domain):
            raise UserError(_('You can\'t create duplicate public holiday '
                              'per year and/or country'))
        return True

    @api.depends('year', 'country_id')
    def _compute_display_name(self):
        for line in self:
            if line.country_id:
                line.display_name = '%s (%s)' % (line.year,
                                                 line.country_id.name)
            else:
                line.display_name = line.year

    def name_get(self):
        result = []
        for rec in self:
            result.append((rec.id, rec.display_name))
        return result

    @api.model
    def get_holidays_list(self, year, employee_id=None):
        """
        Returns recordset of hr.holidays.public.line
        for the specified year and employee
        :param year: year as string
        :param employee_id: ID of the employee
        :return: recordset of hr.holidays.public.line
        """
        holidays_filter = [('year', '=', year)]
        employee = False
        if employee_id:
            employee = self.env['hr.employee'].browse(employee_id)
            if employee.address_id and employee.address_id.country_id:
                holidays_filter.append('|')
                holidays_filter.append(('country_id', '=', False))
                holidays_filter.append(('country_id', '=', employee.address_id.country_id.id))
            else:
                holidays_filter.append(('country_id', '=', False))
        pholidays = self.search(holidays_filter)
        if not pholidays:
            return list()

        states_filter = [('year_id', 'in', pholidays.ids)]
        if employee and employee.address_id and employee.address_id.state_id:
            states_filter += ['|',
                              ('state_ids', '=', False),
                              ('state_ids', '=',
                               employee.address_id.state_id.id)]
        else:
            states_filter.append(('state_ids', '=', False))
        hhplo = self.env['hr.holidays.public.line']
        holidays_lines = hhplo.search(states_filter)
        return holidays_lines

    @api.model
    def is_public_holiday(self, selected_date, employee_id=None):
        """
        Returns True if selected_date is a public holiday for the employee
        :param selected_date: datetime object or string
        :param employee_id: ID of the employee
        :return: bool
        """
        if isinstance(selected_date, str):
            selected_date = fields.Date.from_string(selected_date)
        holidays_lines = self.get_holidays_list(
            selected_date.year, employee_id=employee_id)
        if holidays_lines:
            hol_date = holidays_lines.filtered(
                lambda r: r.date == fields.Date.to_string(
                    selected_date))
            if hol_date.ids:
                return True
        return False


class HrHolidaysPublicLine(models.Model):
    _name = 'hr.holidays.public.line'
    _description = 'Public Holidays Lines'
    _order = "date, name desc"

    name = fields.Char('Name', required=True)
    date = fields.Date('Date', required=True)
    year_id = fields.Many2one('hr.holidays.public', 'Calendar Year', required=True)
    variable_date = fields.Boolean('Date may change', default=True)
    state_ids = fields.Many2many('res.country.state', 'hr_holiday_public_state_rel', 'line_id', 'state_id',
                                 'Related States')

    @api.constrains('date', 'state_ids')
    def _check_date_state(self):
        for line in self:
            line._check_date_state_one()

    def _check_date_state_one(self):
        if fields.Date.from_string(self.date).year != self.year_id.year:
            raise UserError(_(
                'Dates of holidays should be the same year '
                'as the calendar year they are being assigned to'
            ))

        if self.state_ids:
            domain = [('date', '=', self.date),
                      ('year_id', '=', self.year_id.id),
                      ('state_ids', '!=', False),
                      ('id', '!=', self.id)]
            holidays = self.search(domain)

            for holiday in holidays:

                if self.state_ids & holiday.state_ids:
                    raise UserError(_('You can\'t create duplicate public '
                                      'holiday per date %s and one of the '
                                      'country states.') % self.date)
        domain = [('date', '=', self.date),
                  ('year_id', '=', self.year_id.id),
                  ('state_ids', '=', False)]
        if self.search_count(domain) > 1:
            raise UserError(_('You can\'t create duplicate public holiday '
                              'per date %s.') % self.date)
        return True
