# -*- coding: utf-8 -*-
##############################################################################
#
#    Purchase - Computed Purchase Order Module for Odoo
#    Copyright (C) 2016-Today: La Louve (<http://www.lalouve.net/>)
#    @author Julien WESTE
#    @author Sylvain LE GAL (https://twitter.com/legalsylvain)
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import _, api, fields, models

from openerp.exceptions import ValidationError
from datetime import datetime
import pytz


STATES = [
    ('cancel', 'Cancelled'),
    ('draft', 'Unconfirmed'),
    ('open', 'Confirmed'),
    ('done', 'Attended'),
    ('absent', 'Absent'),
    ('waiting', 'Waiting'),
    ('excused', 'Excused'),
    ('replaced', 'Replaced'),
    ('replacing', 'Replacing'),
]


class ShiftTemplateRegistrationLine(models.Model):
    _name = 'shift.template.registration.line'
    _description = 'Attendee Line'
    _order = 'date_begin desc'

    registration_id = fields.Many2one(
        'shift.template.registration', string='Registration', required=True,
        ondelete='cascade')
    date_begin = fields.Date("Begin Date", required=True)
    date_end = fields.Date("End Date")
    state = fields.Selection(STATES, string="State", default="open")
    shift_registration_ids = fields.One2many(
        'shift.registration', 'tmpl_reg_line_id',
        'Registrations',)
    partner_id = fields.Many2one(
        related="registration_id.partner_id", store=True)
    shift_template_id = fields.Many2one(
        related="registration_id.shift_template_id")
    shift_ticket_id = fields.Many2one(
        related="registration_id.shift_ticket_id")
    is_current = fields.Boolean(
        string="Current", compute="_compute_current", multi="current")
    is_past = fields.Boolean(
        string="Past", compute="_compute_current", multi="current")
    is_future = fields.Boolean(
        string="Future", compute="_compute_current", multi="current")

    leave_id = fields.Many2one('shift.leave', string='Leave')

    # constraints Section
    @api.multi
    @api.constrains('date_begin', 'date_end')
    def _check_dates(self):
        for leave in self:
            if leave.date_end and leave.date_end < leave.date_begin:
                raise ValidationError(_(
                    "Stop Date should be greater than Start Date."))
            leave._check_over_lap()

    @api.multi
    def _check_over_lap(self):
        self.ensure_one()
        lines = self.partner_id.tmpl_reg_line_ids
        for line in lines:
            if (line.date_begin <= self.date_end or not self.date_end) and\
                (line.date_end >= self.date_begin or not line.date_end) and\
                    line.id != self.id:
                raise ValidationError(_(
                    "You can't register this line because it would " +
                    "create an overlap with another line for this member"))

    @api.multi
    def _compute_current(self):
        for line in self:
            now = fields.Datetime.now()
            line.is_current = False
            line.is_past = False
            line.is_future = False
            if (line.date_begin and line.date_begin > now):
                line.is_future = True
            elif (line.date_end and line.date_end < now):
                line.is_past = True
            else:
                line.is_current = True

    @api.model
    def create(self, vals):
        begin = vals.get('date_begin', False)
        end = vals.get('date_end', False)

        st_reg_id = vals.get('registration_id', False)
        if not st_reg_id:
            shift_template_id = vals.get('shift_template_id', False)
            partner_id = vals.get('partner_id', False)
            reg_ids = self.env['shift.template'].browse(shift_template_id).\
                registration_ids.filtered(
                    lambda r: r.partner_id.id == partner_id)
            st_reg_id = reg_ids and reg_ids[0].id or False
            vals['registration_id'] = st_reg_id
        if not st_reg_id:
            st_reg_id = self.env['shift.template.registration'].with_context({
                'no_default_line': True}).create(
                {
                    'shift_template_id': shift_template_id,
                    'partner_id': partner_id,
                    'shift_ticket_id': vals.get('shift_ticket_id', False),

                }).id
            vals['registration_id'] = st_reg_id

        st_reg = self.env['shift.template.registration'].browse(st_reg_id)
        partner = st_reg.partner_id

        shifts = st_reg.shift_template_id.shift_ids.filtered(
            lambda s, b=begin, e=end: (s.date_begin > b or not b) and
            (s.date_end < e or not e) and (s.state != 'done'))

        v = {
            'partner_id': partner.id,
            'state': vals.get('state', 'open')
        }

        created_registrations = []
        for shift in shifts:
            ticket_id = shift.shift_ticket_ids.filtered(
                lambda t: t.product_id == st_reg.shift_ticket_id.product_id)
            if ticket_id:
                ticket_id = ticket_id[0]
            else:
                shift.write({
                    'shift_ticket_ids': [(0, 0, {
                        'name': st_reg.shift_ticket_id.name,
                        'product_id': st_reg.shift_ticket_id.product_id.id,
                        'seats_max': st_reg.shift_ticket_id.seats_max,
                    })]
                })
                ticket_id = shift.shift_ticket_ids.filtered(
                    lambda t: t.product_id ==
                    st_reg.shift_ticket_id.product_id)[0]
            values = dict(v, **{
                'shift_id': shift.id,
                'shift_ticket_id': ticket_id.id,
                'template_created': True,
            })
            created_registrations.append((0, 0, values))

        vals['shift_registration_ids'] = created_registrations
        return super(ShiftTemplateRegistrationLine, self.with_context(
            dict(self.env.context, **{'creation_in_progress': True}))).create(
            vals)

    @api.multi
    def write(self, vals):
        res = super(ShiftTemplateRegistrationLine, self).write(vals)
        self.mapped(lambda s: s.partner_id)._compute_registration_counts()
        for line in self:
            bypass_leave_change_check = self._context.get(
                'bypass_leave_change_check', False)
            if not bypass_leave_change_check and line.leave_id:
                raise ValidationError(_(
                    "You cannot make changes on this template registration. "
                    "Please make your changes directly on the leave recorded "
                    "for this period. You will need to cancel it then set to "
                    "draft before you can make required changes."))

            sr_obj = self.env['shift.registration']
            st_reg = line.registration_id
            partner = st_reg.partner_id

            state = vals.get('state', line.state)
            begin = vals.get('date_begin', line.date_begin)
            end = vals.get('date_end', line.date_end)

            # for linked registrations
            for sr in line.shift_registration_ids:
                shift = sr.shift_id

                # Convert the datetime in shift to local date
                shift_date_begin = self.convert_local_date(shift.date_begin)
                shift_date_end = self.convert_local_date(shift.date_end)

                # if shift is done, pass
                if shift.state == "done":
                    continue
                # if dates ok, just update state
                if sr.state in ['draft', 'open', 'waiting']:
                    if (shift_date_begin >= begin or not begin) and\
                            (shift_date_end <= end or not end):
                        sr.state = state
                    # if dates not ok, unlink the shift_registration
                    else:
                        sr.unlink()

            # for shifts within dates: if partner has no registration, create
            # it
            shifts = st_reg.shift_template_id.shift_ids.filtered(
                lambda s, b=begin, e=end: (
                    self.convert_local_date(s.date_begin) >= b or not b) and (
                    self.convert_local_date(s.date_end) <= e or not e) and (
                    s.state != 'done'))

            for shift in shifts:
                found = partner_found = False
                for registration in shift.registration_ids:
                    if registration.partner_id == partner:
                        partner_found = registration
                    if registration.tmpl_reg_line_id == line:
                        found = True
                        break

                if not found:
                    if partner_found:
                        partner_found.tmpl_reg_line_id = line
                        partner_found.state = state
                    else:
                        ticket_id = shift.shift_ticket_ids.filtered(
                            lambda t: t.product_id ==
                            st_reg.shift_ticket_id.product_id)[0]
                        values = {
                            'partner_id': partner.id,
                            'state': state,
                            'shift_id': shift.id,
                            'shift_ticket_id': ticket_id.id,
                            'tmpl_reg_line_id': line.id,
                            'template_created': True,
                        }
                        sr_obj.create(values)
        return res

    @api.multi
    def unlink(self):
        for strl in self:
            for reg in strl.shift_registration_ids:
                reg.unlink()
        return super(ShiftTemplateRegistrationLine, self).unlink()

    @api.model
    def convert_local_date(self, timeutc):
        '''
        @Function to convert UTC time to Local Time and return the local date
        '''
        if not timeutc:
            return False
        tz_name = self._context.get('tz') or self.env.user.tz
        dateutc_obj = datetime.strptime(timeutc, '%Y-%m-%d %H:%M:%S')
        utc_timestamp = pytz.utc.localize(
            dateutc_obj, is_dst=False)
        context_tz = pytz.timezone(tz_name)
        datelocal_obj = utc_timestamp.astimezone(context_tz)

        return datelocal_obj.strftime('%Y-%m-%d')