# -*- coding: utf-8 -*-
###############################################################################
#
#    Tech-Receptives Solutions Pvt. Ltd.
#    Copyright (C) 2009-TODAY Tech-Receptives(<http://www.techreceptives.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
import time
import datetime
from dateutil.relativedelta import relativedelta
import werkzeug
from urlparse import urljoin
from odoo.osv import expression
from odoo.tools.float_utils import float_round as round
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT,DEFAULT_SERVER_DATE_FORMAT
from odoo.exceptions import UserError, ValidationError
from odoo import api, fields, models, _
from odoo.tools.misc import formatLang
import json,logging
import uuid
_logger = logging.getLogger(__name__)

class EtourismAVTBookingRequest(models.Model):
    _name = 'etourism.avt.booking.request'
    _rec_name = "request_no"
    _order = "request_date desc"
    _inherit = 'mail.thread'
    _description = "Booking Request"

    num_pax = fields.Integer(string='Number of Pax')
    request_no = fields.Char('Request No', size=64, readonly=True)
    enterprise_id = fields.Many2one('etourism.enterprise', 'Enterprise')
    has_default_enterprise = fields.Boolean('Has Default Enterprise',
                                            help="True, if User creating Booking has related Enterprise.")
    request_date = fields.Datetime('Request Date', required=True, readonly=True,default=(lambda *a: time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)))
    date = fields.Datetime(string='Event Date', default=(lambda *a:time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)))
    client_id = fields.Many2one('res.partner', 'Client', required=True)
    description = fields.Text(string='Description')

    @api.model
    def default_get(self, fields):
        res = super(EtourismAVTBookingRequest, self).default_get(fields)
        if self.env.uid:
            enterprise_id = self.env['res.users'].browse([self.env.uid])[0].enterprise_id
            if enterprise_id:
                res.update({'enterprise_id': enterprise_id.id, 'has_default_enterprise': True})
        return res

    @api.model
    def create(self, vals):
        print "########################### CREATE BOOKING REQUEST ###########################: ", vals

        vals['request_no'] = self.env['ir.sequence'].get('etourism.avt.booking.request')
        booking = super(EtourismAVTBookingRequest, self).create(vals)

        _logger.info('Sending Email notification on new booking registration. Booking Id: %s' % (booking.id))
        booking.send_email_notification('mail_template_etourism_avt_booking_request')
        booking.send_email_notification('mail_template_etourism_avt_booking_request_enterprise')

        return booking

    @api.multi
    def get_signup_url(self):
        partner = self.client_id
        base_url = self.env['ir.config_parameter'].get_param('web.base.url')
        route = 'login'
        # the parameters to encode for the query
        query = dict(db=self.env.cr.dbname)
        # if partner.signup_token and signup_type:
        #    query['token'] = partner.signup_token

        fragment = dict()
        base = '/web#'
        fragment['view_type'] = 'form'
        # fragment['menu_id'] = menu_id
        fragment['model'] = self._name
        fragment['id'] = self.id

        query['redirect'] = base + werkzeug.url_encode(fragment)

        result = urljoin(base_url, "/web/%s?%s" % (route, werkzeug.url_encode(query)))

        return result

    @api.multi
    def get_date_string(self):
        lang_code = self.env.user.lang or 'en_US'
        lang_ids = self.env['res.lang'].search([('code', '=', lang_code)], limit=1)
        date_format = lang_ids.date_format or DEFAULT_SERVER_DATE_FORMAT

        def formatLangDate( date ):
            date = str(datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S").date())
            date_dt = datetime.datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT)
            return date_dt.strftime(date_format.encode('utf-8')).decode('utf-8')

        date = ''
        for request in self:
            date = str(formatLangDate(request.date))

        return date

    @api.multi
    def get_ebusiness_contact_emails(self):
        for request in self:
            ebusiness_id = request.enterprise_id.ebusiness_id
            contact_emails = []

            for contact in ebusiness_id.contacts_line:
                if contact.send_email:
                    contact_emails.append(contact.email)
            return ', '.join(contact_emails)

    @api.multi
    def send_email_notification(self, email_template=False):
        print "send_email_notification"
        if email_template:
            ir_model_data = self.env['ir.model.data']
            try:
                template_id = ir_model_data.get_object_reference('etourism_mail_notification', email_template)[1]
            except ValueError:
                template_id = False

            if template_id:
                mail_template = self.env['mail.template']
                template_ids = mail_template.browse(template_id)
                template_ids.with_context({'ltgt_replace': True, 'enterprise_name': self.enterprise_id.name}).send_mail(
                    self.id, force_send=True)
            else:
                _logger.error('Email template not found. Template: %s Booking Id: %s' % (email_template, self.id))
        return False


class EtourismAVTBooking(models.Model):
    _name = 'etourism.avt.booking'
    _rec_name = "reservation_no"
    _order = "booking_date desc"
    _inherit = 'mail.thread'
    _description = "Booking"

    name = fields.Char(string='Name')
    reservation_no = fields.Char('Reservation No', size=64, readonly=True)
    enterprise_id = fields.Many2one('etourism.enterprise', 'Enterprise')
    booking_date = fields.Datetime('Booking Date', required=True, readonly=True,default=(lambda *a:time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)))
    date = fields.Datetime(string='Event Date',default=(lambda *a:
                                          time.strftime
                                          (DEFAULT_SERVER_DATETIME_FORMAT)))
    package_id = fields.Many2one('etourism.avt.package', 'Package',required=True)
    state = fields.Selection([('new', 'New'),('pending', 'Pending'),('confirmed', 'Confirmed'),('paid','Paid'),('accomplished', 'Accomplished'),('no_show', 'No Show'),('cancelled', 'Cancelled')], 'State', default='pending', track_visibility='onchange',translate=False)
    total_amount = fields.Float('Total Amount',store=True)
    num_pax = fields.Integer(string='Number of Pax',default=1)
    client_id= fields.Many2one('res.partner', 'Client',required=True)
    pricelist_item_id = fields.Many2one('product.pricelist.item', 'Pricelist Item',required=True)
    booking_condition_id = fields.Many2one('etourism.booking.condition', related="pricelist_item_id.booking_condition_id", string='Booking Condition', store=True)
    unitary_amount = fields.Float('Amount P/Pax', related='pricelist_item_id.fixed_price', readonly=True)
    pax_line = fields.One2many('etourism.avt.booking.pax', 'booking_id', string="Pax(s)")
    pax_ids = fields.Many2many('res.partner', 'etourism_booking_res_partner_rel','booking_id', 'partner_id',string='Pax (s)')
    origin = fields.Selection([('api', 'API'),('tms', 'TMS')], 'Origin', default='tms', track_visibility='onchange',translate=False)
    island_id = fields.Many2one('ecom.location', related="enterprise_id.island_id", string='Island', store=True)
    county_id = fields.Many2one('ecom.location', related="enterprise_id.county_id", string='County', store=True)
    description = fields.Text(string='Description')
    has_default_enterprise = fields.Boolean('Has Default Enterprise', help="True, if User creating Booking has related Enterprise.")
    discount_amount = fields.Float('Discount Amount',store=True, readonly=True)
    voucher_id = fields.Many2one('etourism.avt.voucher', 'Voucher')
    token = fields.Char('Reservation Token', default=lambda self: str(uuid.uuid4().hex), readonly=True, required=True,
                        copy=False)


    @api.multi
    def get_total_amount(self):
        total, currency_id = 0.0, False
        for booking in self:
            currency_id = booking.pricelist_item_id.pricelist_id.currency_id
            total = (booking.pricelist_item_id.fixed_price * booking.num_pax) - booking.discount_amount
        total = formatLang(self.env, total, currency_obj=currency_id)
        return total


    @api.multi
    def get_subtotal(self):
        total, currency_id = 0.0, False
        for booking in self:
            currency_id = booking.pricelist_item_id.pricelist_id.currency_id
            total = (booking.pricelist_item_id.fixed_price * booking.num_pax)
        total = formatLang(self.env, total, currency_obj=currency_id)
        return total

    @api.onchange('voucher_id')
    def apply_voucher(self):
        if self.voucher_id and self.voucher_id.price_item_id !=self.pricelist_item_id:
            self.voucher_id = None
            self.discount_amount = None
            raise ValidationError('Voucher is not valid')
        elif self.voucher_id.usage and self.voucher_id.voucher_used:
            raise ValidationError('Voucher expired')
        elif self.voucher_id:
            self.discount_amount = self.voucher_id.value if int(self.voucher_id.type)==1 else (self.voucher_id.value * self.total_amount)/100
            self.total_amount = self.total_amount - self.discount_amount
            if self.total_amount >= 0:
                self.voucher_id.voucher_used = True
                if self.voucher_id.usage:
                    self.voucher_id.action_close()
        else:
            self.onchange_pricelist_item_id()
            self.discount_amount = None

        if self.total_amount < 0:
            self.total_amount = self.pricelist_item_id.fixed_price * self.num_pax
            self.discount_amount = 0
            self.voucher_id = None
            raise ValidationError("Discount amount is greater than total amount, can't apply this voucher!")


    @api.model
    def default_get(self, fields):
        print "AVT BOOKING DEFAULT GET: ",fields
        res = super(EtourismAVTBooking, self).default_get(fields)
        if self.env.uid:
            enterprise_id = self.env['res.users'].browse([self.env.uid])[0].enterprise_id
            if enterprise_id:
                res.update({'enterprise_id': enterprise_id.id, 'has_default_enterprise': True})
        print "RES: ",res
        return res

    @api.multi
    def send_email_notification(self, email_template=False):
        if email_template:
            ir_model_data = self.env['ir.model.data']
            try:
                template_id = ir_model_data.get_object_reference('etourism_mail_notification', email_template)[1]
            except ValueError:
                template_id = False

            if template_id:
                mail_template = self.env['mail.template']
                template_ids = mail_template.browse(template_id)
                template_ids.with_context({'ltgt_replace': True, 'enterprise_name': self.enterprise_id.name}).send_mail(
                    self.id, force_send=True)
            else:
                _logger.error('Email template not found. Template: %s Booking Id: %s' % (email_template, self.id))
        return False

    @api.onchange('pricelist_item_id')
    def onchange_pricelist_item_id(self):
        if not (self.pricelist_item_id):
            return {'value': {}}
        else:
            self.total_amount = self.pricelist_item_id.fixed_price * self.num_pax
            self.package_id=self.pricelist_item_id.package_id
            if self.pricelist_item_id.min_quantity>self.num_pax or self.pricelist_item_id.max_occupancy < self.num_pax:
                self.num_pax = self.pricelist_item_id.min_quantity
                print "MIN PAX: ",self.num_pax

    @api.onchange('date')
    def onchange_date(self):
        if not (self.date and self.enterprise_id and self.pricelist_item_id):
            return {'value': {}}
        else:
            pricelist_start = self.pricelist_item_id.pricelist_id.start_date
            pricelist_end = self.pricelist_item_id.pricelist_id.end_date

            if pricelist_start>self.date or pricelist_end<self.date:
                self.pricelist_item_id = None
                self.package_id = None

    @api.onchange('num_pax')
    def onchange_num_pax(self):
        if self.num_pax <= 0:
            self.num_pax=0
            raise ValidationError('Number of Pax must be greater then 0')
        else:
            if self.pricelist_item_id:
                print "NUM PAX: ",self.num_pax
                self._cr.execute("select id from product_pricelist_item "
                                 "where pricelist_id=%s and max_occupancy>=%s \
                                  order by max_occupancy asc limit 1",
                                 (self.pricelist_item_id.pricelist_id.id, self.num_pax))
                res = self._cr.fetchone()
                print "MAX: ",res
                if res:
                    self.pricelist_item_id = res[0]
                    #self.package_id=self.pricelist_item_id.package_id
                    print "MAX PRICE: ", self.pricelist_item_id
                else:
                    print "ELS MAX PRICE: ", self.pricelist_item_id
                    self.pricelist_item_id = None
                    self.num_pax = None
                    raise ValidationError('No Price List defined for this number of Pax')
                self.total_amount = self.pricelist_item_id.fixed_price * self.num_pax

    @api.onchange('package_id')
    def onchange_package_id(self):
        print "PACKAGE ID CHANGE"
        if not self.package_id:
            return {'value': {}}
        else:
            print "PACKAGE ITEM NONE"
            self.pricelist_item_id=None
            self.total_amount=0

    @api.multi
    def action_confirmed(self):
        self.write({'state': 'confirmed'})
        return True

    @api.multi
    def action_pay(self):
        self.write({'state': 'paid'})
        return True

    @api.multi
    def action_no_show(self):
        from_dt = datetime.date.today()
        date = datetime.datetime.strptime(self.date, '%Y-%m-%d %H:%M:%S').date()
        if from_dt < date:
            raise ValidationError('You cannot set a No Show before checkin date.')
        else:
            self.write({'state': 'no_show'})
        return True

    @api.multi
    def action_cancelled(self):
        print ("CANCEL BOOKING REGISTRATION")
        self.write({'state': 'cancelled'})
        return True

    @api.multi
    def action_hosted(self):
        from_dt = datetime.date.today()
        date = datetime.datetime.strptime(self.date, '%Y-%m-%d %H:%M:%S').date()
        if from_dt < date:
            raise ValidationError('You cannot checkin before checkin date.')
        else:
            self.write({'state': 'accomplished'})
        return True

    @api.model
    def create(self, vals):
        print "########################### CREATE BOOKING ###########################: ",vals
        """
            Overrides orm create method.
            @param self: The object pointer
            @param vals: dictionary of fields value.
            """
        if not vals:
            vals = {}
        if self._context is None:
            self._context = {}
        if 'package_id' not in vals:
            raise ValidationError('You tried to add reservation without selecting a package')
        if not vals['client_id']:
            raise ValidationError('You tried to add reservation without selecting a Client')
        if 'pricelist_item_id' not in vals:
            raise ValidationError('You tried to add reservation without price list item')
        if 'date' not in vals:
            raise ValidationError('You tried to add reservation without  Event Date')
        if 'num_pax' not in vals:
            raise ValidationError('You tried to add reservation without Number of Pax')
        if vals['num_pax']<=0:
            raise ValidationError('Number of Pax must be greater then 0')

        pricelist_item = self.env['product.pricelist.item'].browse([vals['pricelist_item_id']])[0]

        if 'total_amount' not in vals:
            vals['total_amount'] = pricelist_item.fixed_price * int(vals['num_pax'])

        if 'voucher_id' in vals and vals['voucher_id']:
            print "######### VOUCHER: ", vals['voucher_id']
            voucher_id = self.env['etourism.avt.voucher'].browse([vals['voucher_id']])[0]
            print "######### VOUCHER: ", voucher_id
            voucher_validation = voucher_id.validate()
            print "VOUCHER: ", voucher_validation
            '''if voucher_id and not voucher_validation['valid']:
                raise ValidationError(voucher_validation['message'])
            else:
                voucher_id.voucher_used = True'''

        vals['state'] = 'pending'

        try:
            vals['date'] = datetime.datetime.strptime(vals['date'], '%Y-%m-%d %H:%M:%S').replace(hour=12, minute=00, second=00)
        except:
            vals['date']=datetime.datetime.strptime(vals['date'], "%Y/%m/%d").replace(hour=12, minute=00, second=00)
            
        vals['reservation_no'] = self.env['ir.sequence'].get('etourism.avt.booking')

        record =super(EtourismAVTBooking, self).create(vals)
        if 'voucher_id' in vals:
            record.apply_voucher()

        return record



class EtourismBookingGuest(models.Model):
    _name = 'etourism.avt.booking.pax'
    _rec_name = 'partner_id'

    booking_id = fields.Many2one('etourism.avt.booking', 'Booking')
    partner_id = fields.Many2one('res.partner', 'Guest', required=True)
    id_number = fields.Char(related='partner_id.id_number', string='ID Number', store=True)
    email = fields.Char(related='partner_id.email', string='Email', store=True)
    phone = fields.Char(related='partner_id.phone', string='Phone', store=True)
    mobile = fields.Char(related='partner_id.mobile', string='Mobile', store=True)
    nationality_id = fields.Many2one('res.country', 'Nationality')
    origin_id = fields.Many2one('res.country', 'Place of origin')
    state = fields.Selection(string='State', related='booking_id.state', store=True)