from trytond.pool import Pool, PoolMeta
from trytond.model import (
    ModelSQL, ModelView, Workflow, fields)
from trytond.modules.company import CompanyReport
from trytond.pyson import Eval, If, Bool
from trytond.modules.company.model import set_employee
from trytond.exceptions import UserError
from trytond.transaction import Transaction
from trytond.wizard import (
    Button, StateAction, StateTransition, StateView, Wizard)

from trytond.modules.currency.fields import Monetary
from trytond.modules.product import price_digits

import datetime
from datetime import timedelta


class Contract(Workflow, ModelSQL, ModelView):
    'Contracts'
    __name__ = 'optical_equipment.contract'
    _rec_name = 'number'
    _order_name = 'number'

    
    company = fields.Many2One(
        'company.company', "Company", required=True, select=True,
        states={
            'readonly': (Eval('state') != 'draft') | Eval('party', True),
            },help="Make the subscription belong to the company.")
    number = fields.Char(
        "Number", readonly=True, select=True,
        help="The main identification of the subscription.")
    reference = fields.Char(
          "Reference", select=True,
        help="The identification of an external origin.")
    description = fields.Char("Description",
        states={
            'readonly': Eval('state') != 'draft',
            })
    party = fields.Many2One(
        'party.party', "Party", required=True,
        states={
            'readonly': (Eval('state') != 'draft') | Eval('party', True),
            },help="The party who subscribes.")
    contact = fields.Many2One('party.contact_mechanism', "Contact", required=True)
    invoice_address = fields.Many2One('party.address', 'Invoice Address',
                                      required=True, domain=[('party', '=', Eval('party'))],
                                      states={
                                          'readonly': (Eval('state') != 'draft') | Eval('party', True),
                                      })
    start_date = fields.Date("Start Date", required=True,)
    end_date = fields.Date("End Date",
                           domain=['OR',
                                   ('end_date', '>=', If(
                                       Bool(Eval('start_date')),
                                       Eval('start_date', datetime.date.min),
                                       datetime.date.min)),
                                   ('end_date', '=', None),
                                   ],
                           states={
                               'readonly': Eval('state') != 'draft',
                           })
    maintenance_services = fields.Many2Many('optical_equipment_maintenance.service-equipment.contract',
                                            'contract', 'maintenance_services', "Prorogues",
                                            states={'readonly': Eval('state') != 'draft'})
    equipments = fields.One2Many('optical_equipment.equipment', 'contract', "Equipments",
            states={'readonly': Eval('state') != 'draft'})
    price_contract = Monetary("Price Contract", digits=price_digits, currency='currency', required=True,
                          states={'readonly': Eval('state') != 'draft'})
    state = fields.Selection([
            ('draft', "Draft"),
            ('running', "Running"),
            ('closed', "Closed"),
            ('cancelled', "Cancelled"),
            ], "State", readonly=True, required=False, sort=False,
                             help="The current state of the subscription.")


    @classmethod
    def __setup__(cls):
        super(Contract, cls).__setup__()
        cls._order = [
            ('number', 'DESC NULLS FIRST'),
            ('id', 'DESC'),
            ]
        cls._transitions = ({
            ('draft', 'running'),
            ('running', 'draft'),
            ('running', 'closed'),
            ('running', 'cancelled'),
        })
        cls._buttons.update({
            'draft': {'invisible': Eval('state').in_(['draft','closed'])},
            'running': {'invisible': Eval('state').in_(['cancelled', 'running'])},
            'cancelled': {'invisible': Eval('state').in_(['draft', 'cancelled'])}
        })


    @staticmethod
    def default_company():
        return Transaction().context.get('company')

    @staticmethod
    def default_state():
        return 'draft'

    @classmethod
    def set_number(cls, contracts):
        pool = Pool()
        Config = pool.get('optical_equipment.configuration')
        config = Config(4)
        
        if config.contract_sequence != None:
            if not contracts[0].number:
                try:
                    contracts[0].number = config.contract_sequence.get()
                    cls.save(contracts)
                except UserError:
                    raise UserError(str('Validation Error'))
        else:
            raise UserError(gettext('optical_equipment.msg_not_sequence_equipment'))

    @classmethod
    @ModelView.button
    @Workflow.transition('draft')
    def draft(cls, contracts):
        contract = contracts[0]
        for equipment in contract.equipments:
            equipment.state = "uncontrated"
            equipment.contract_history += (contract.id,)
            equipment.save()


    @classmethod
    @ModelView.button
    @Workflow.transition('running')
    def running(cls, contracts):
        contract = contracts[0]
        for equipment in contract.equipments:
            equipment.state = "contrated"
            equipment.contract_history += (contract.id,)
            equipment.save()

        cls.set_number(contracts)
        contract.state='running'
        contract.save()

    @classmethod
    @ModelView.button
    @Workflow.transition('cancelled')
    def cancelled(cls, contracts):
        pass

        
class ContractMaintenanceServices(ModelSQL):
    'Contract - Maintenance Services'
    __name__ = 'optical_equipment_maintenance.service-equipment.contract'

    maintenance_services = fields.Many2One('optical_equipment_maintenance.service', "Maintenance Service", select=True)
    contract = fields.Many2One('optical_equipment.contract', "Contract")

    
class ContractEquipment(ModelSQL):
    'Optical Equipment - Contract'
    __name__ = 'optical_equipment.contract-optical_equipment.equipment'
    
    equipment = fields.Many2One('optical_equipment.equipment', 'Equipment', select=True)
    contract = fields.Many2One('optical_equipment.contract', 'Contract', select=True)

    
class ContractReport(CompanyReport):
    __name__ = 'optical_equipment.contract'

    @classmethod
    def execute(cls, ids, data):
        with Transaction().set_context(address_with_party=True):
            return super(ContractReport, cls).execute(ids, data)

    @classmethod
    def get_context(cls, records, header, data):
        pool = Pool()
        Date = pool.get('ir.date')
        context = super().get_context(records, header, data)
        context['today'] = Date.today()

        return context

    
class CreateContractInitial(ModelView, ModelSQL):
    'Create Contract Inicial'
    __name__ = 'optical_equipment_create.contract'

    currency = fields.Many2One('currency.currency', 'Currency', required=True)
    company = fields.Many2One(
        'company.company', "Company", readonly=True, required=True, select=True,
        states={
            'readonly': (Eval('state') != 'draft') | Eval('party', True),
            },help="Make the subscription belong to the company.")
    party = fields.Many2One(
        'party.party', "Party", required=True,
        help="The party who subscribes.")
    invoice_address = fields.Many2One('party.address', 'Invoice Address',
                                      required=True, domain=[('party', '=', Eval('party'))])
    payment_term = fields.Many2One('account.invoice.payment_term',
        'Payment Term')
    contact = fields.Many2One(
        'party.contact_mechanism', "Contact", required=True,
        domain=[('party', '=', Eval('party'))],
        context={
            'company': Eval('company', -1),
            })
    start_date = fields.Date("Start Date", required=True)
    end_date = fields.Date("End Date",
                           domain=['OR',
                                   ('end_date', '>=', If(
                                       Bool(Eval('start_date')),
                                       Eval('start_date', datetime.date.min),
                                       datetime.date.min)),
                                   ('end_date', '=', None),
                                   ])
    unit_price = Monetary("Unit Price", digits=price_digits, currency='currency', required=True)
    
    @staticmethod
    def default_company():
        return Transaction().context.get('company')

    @staticmethod
    def default_currency():
        Company = Pool().get('company.company')
        if Transaction().context.get('company'):
            company = Company(Transaction().context['company'])
            return company.currency.id
    
    @classmethod
    def default_start_date(cls):
        pool = Pool()
        Date = pool.get('ir.date')
        return Date.today()

    
    @fields.depends('party')
    def on_change_party(self):
        pool = Pool()
        Date = pool.get('ir.date')
        if self.party:
            self.invoice_address = self.party.address_get(type='invoice')
            if self.party.customer_type == "ips": 
                self.end_date =  Date.today() + timedelta(days=182)
            else:
                self.end_date =  Date.today() + timedelta(days=365)

            
class CreateContract(Wizard):
    __name__ = 'optical_equipment.maintenance.contract'

    start = StateView('optical_equipment_create.contract',
                      'optical_equipment.create_contract_view_form',[
                          Button('Cancel', 'end', 'tryton-cancel'),
                          Button('Create', 'create_contract', 'tryton-ok', default=True),
                      ])
    create_contract = StateAction('optical_equipment.act_contract_form')


    def default_start(self, fields):
        if self.record:
            default = {'party': self.record.propietary.id,
                       'invoice_address': self.record.propietary_address.id,
                       'unit_price': (self.record.sale_origin.amount
                                      if self.record.sale_origin.__name__ == "sale.line"
                                      else self.record.sale_origin.total_amount),
                       }
            return default
        
    @property
    def _subscription_start(self):
        return dict(
            party=self.start.party,
            contact=self.start.contact,
            start_date=self.start.start_date,
            end_date=self.start.end_date,
            invoice_address=self.start.invoice_address,
            unit_price=self.start.unit_price
        )
    
    def do_create_contract(self, action):
        maintenance_service = self.records[0]
        pool = Pool()
        Contract = pool.get('optical_equipment.contract')

        dates = self._subscription_start

        prorogues = (maintenance_service,)
        equipments = []
        for line in maintenance_service.lines:
            equipments.append(line.equipment.id)
            
        if maintenance_service.contract_origin:
            contract=maintenance_service.contract_origin
            contract.invoice_address=dates['invoice_address']
            contract.contact=dates['contact']
            contract.start_date=dates['start_date']
            contract.end_date=dates['end_date']
            contract.maintenance_services+=prorogues
            contract.equipments=equipments
            contract.state='draft'
            contract.price_contract=dates['unit_price']
            #contract.price_contract=maintenance_service.sale_origin.sale.total_amount
            contract.save()
        else:
            contract = Contract(party=dates['party'],
                            invoice_address=dates['invoice_address'],
                            contact=dates['contact'],
                            start_date=dates['start_date'],
                            end_date=dates['end_date'],
                            maintenance_services=prorogues,
                            equipments=equipments,
                            state='draft',
                            price_contract=maintenance_service.sale_origin.sale.total_amount
                            )
            contract.save()