import time
import math

from odoo.osv import expression
from odoo.tools.float_utils import float_round as round
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import UserError, ValidationError
from odoo import api, fields, models, _
from datetime import datetime
from dateutil.relativedelta import relativedelta

class AccountModel(models.Model):
    _name = "account.model"
    _description = "Account Model"
        
    name        = fields.Char(string='Model Name', required=True, help="This is a model for recurring accounting entries")
    journal_id  = fields.Many2one('account.journal', string='Journal', required=True)
    company_id  = fields.Many2one('res.company',related='journal_id.company_id',string='Company', store=True, readonly=True)
    lines_id    = fields.One2many('account.model.line', 'model_id', 'Model Entries', copy=True)
    legend      = fields.Text(string='Legend', readonly=True, size=100, 
                              default="You can specify year, month and date in the name of the model using the following labels:\n\n%(year)s: To Specify Year \n%(month)s: To Specify Month \n%(date)s: Current Date\n\ne.g. My model on %(date)s")
    
    @api.onchange('journal_id')
    def onchange_journal_id(self):
        journal_id = self.journal_id
        company_id = False

        if journal_id:
            journal = journal_id
            if journal.company_id.id:
                company_id = journal.company_id.id
        company_id = self.company_id
        
    @api.multi
    def generate(self, data=None):
        if data is None:
            data = {}
        move_ids = []
        entry = {}
        account_move_obj = self.env['account.move']
        account_move_line_obj = self.env['account.move.line']
        pt_obj = self.env['account.payment.term']
        #period_obj = self.env['account.period']

        #context = dict(context or {})
        context = dict(self._context or {})

        if data.get('date', False):
            #context = dict(context)
            context = dict(self._context)
            context.update({'date': data['date']})

        move_date = context.get('date', time.strftime('%Y-%m-%d'))
        
        print "move_date----->>", move_date
        
        move_date = datetime.strptime(move_date,"%Y-%m-%d")
        for model in self:
            ctx = context.copy()
            ctx.update({'company_id': model.company_id.id})
            ctx.update({'journal_id': model.journal_id.id})
            ctx['check_move_validity'] = False
            try:
                entry['name'] = model.name%{'year': move_date.strftime('%Y'), 'month': move_date.strftime('%m'), 'date': move_date.strftime('%Y-%m')}
            except:
                raise UserError(_('Wrong Model!'), _('You have a wrong expression "%(...)s" in your model!'))
            move = account_move_obj.create({
                'ref': entry['name'],
                'journal_id': model.journal_id.id,
                #'date': '2017-01-01'
                'date': context.get('date', fields.Date.context_today(self))
                #default=lambda self: self._context.get('date', fields.Date.context_today(self))
            })
            move_ids.append(move.id)
            
            print "move_ids------->>", move_ids
            print "model.lines_id---->>", model.lines_id
            for line in model.lines_id:
                print "line----->>", line
                analytic_account_id = False
                if line.analytic_account_id:
                    if not model.journal_id.analytic_journal_id:
                        raise UserError(_('No Analytic Journal!'),_("You have to define an analytic journal on the '%s' journal!") % (model.journal_id.name,))
                    analytic_account_id = line.analytic_account_id.id
                val = {
                    'move_id': move.id,
                    'journal_id': model.journal_id.id,
                    'analytic_account_id': analytic_account_id
                }
 
                #date_maturity = context.get('date',time.strftime('%Y-%m-%d'))
                if line.date_maturity == 'partner':
                    if not line.partner_id:
                        raise UserError(_('Error!'), _("Maturity date of entry line generated by model line '%s' of model '%s' is based on partner payment term!" \
                                                                "\nPlease define partner on it!")%(line.name, model.name))
 
#                     payment_term_id = False
#                     if model.journal_id.type in ('purchase', 'purchase_refund') and line.partner_id.property_supplier_payment_term:
#                         payment_term_id = line.partner_id.property_supplier_payment_term.id
#                     elif line.partner_id.property_payment_term:
#                         payment_term_id = line.partner_id.property_payment_term.id
#                     if payment_term_id:
#                         pterm_list = pt_obj.compute(cr, uid, payment_term_id, value=1, date_ref=date_maturity)
#                         if pterm_list:
#                             pterm_list = [l[0] for l in pterm_list]
#                             pterm_list.sort()
#                             date_maturity = pterm_list[-1]
 
                val.update({
                    'name': line.name,
                    'quantity': line.quantity,
                    'debit': line.debit,
                    'credit': line.credit,
                    'account_id': line.account_id.id,
                    #'move_id': move.id,
                    'partner_id': line.partner_id.id,
                    #'date': context.get('date', fields.date.context_today(self,cr,uid,context=context)),
                    #'date': '2017-01-01',
                    #'date_maturity': date_maturity
                })
                print "XXXXXXXXXXXX", val
                move_line_id = account_move_line_obj.with_context(ctx).create(val)
                #aml_obj.with_context(check_move_validity=False).create(aml_dict)
 
        print "move_ids------->>", move_ids
        print "########END##########"
        return move_ids
    
class AccountModelLine(models.Model):
    _name = "account.model.line"
    _description = "Account Model Entries"
    _order = 'sequence'
        
    name        = fields.Char(string='Name', required=True)
    sequence    = fields.Integer(string='Sequence', required=True, help="The sequence field is used to order the resources from lower sequences to higher ones.")
    quantity    = fields.Float(string='Quantity', help="The optional quantity on entries.")
    debit       = fields.Float(string='Debit')
    credit      = fields.Float(string='Credit')
    account_id  = fields.Many2one('account.account', string='Account', required=True, ondelete="cascade")
    analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', ondelete="cascade")
    model_id        = fields.Many2one('account.model', string='Model', required=True, ondelete="cascade", select=True)
    amount_currency = fields.Float(string='Amount Currency', help="The amount expressed in an optional other currency.")
    currency_id     = fields.Many2one('res.currency', string='Currency')
    partner_id      = fields.Many2one('res.partner', string='Partner')
    date_maturity   = fields.Selection([('today','Date of the day'), ('partner','Partner Payment Term')], string='Maturity Date', help="The maturity date of the generated entries for this model. You can choose between the creation date or the creation date of the entries plus the partner payment terms.")
    
    _sql_constraints = [
        ('credit_debit1', 'CHECK (credit*debit=0)',  'Wrong credit or debit value in model, they must be positive!'),
        ('credit_debit2', 'CHECK (credit+debit>=0)', 'Wrong credit or debit value in model, they must be positive!'),
    ]
    
class AccountSubscription(models.Model):
    _name = "account.subscription"
    _description = "Account Subscription"
    
    name        = fields.Char(string='Name', required=True)
    ref         = fields.Char(string='Reference')
    model_id    = fields.Many2one('account.model', string='Model', required=True)
    date_start  = fields.Date(string='Start Date', required=True, default=fields.Date.context_today)
    period_total= fields.Integer(string='Number of Periods', required=True,default=12)
    period_nbr  = fields.Integer(string='Period', required=True,default=1)
    period_type = fields.Selection([('day','days'),('month','month'),('year','year')], string='Period Type', required=True,default='month')
    state       = fields.Selection([('draft','Draft'),('running','Running'),('done','Done')], string='Status', required=True, readonly=True, copy=False,default='draft')
    lines_id    = fields.One2many('account.subscription.line', 'subscription_id', string='Subscription Lines', copy=True)
    
    @api.multi
    def state_draft(self):
        self.write({'state':'draft'})
        return False
    
    @api.multi
    def check(self):
        todone = []
        for sub in self:
            ok = True
            for line in sub.lines_id:
                if not line.move_id.id:
                    ok = False
                    break
            if ok:
                todone.append(sub.id)
        if todone:
            todone_ids = self.browse(todone)
            todone_ids.write(todone, {'state':'done'})
        return False
    
    @api.multi
    def remove_line(self):
        toremove = []
        for sub in self:
            for line in sub.lines_id:
                if not line.move_id.id:
                    toremove.append(line.id)
        if toremove:
            sub_line = self.env['account.subscription.line'].browse(toremove)
            sub_line.unlink()
        self.write({'state':'draft'})
        return False
    
    @api.multi
    def compute(self):
        for sub in self:
            ds = sub.date_start
            for i in range(sub.period_total):
                self.env['account.subscription.line'].create({
                    'date': ds,
                    'subscription_id': sub.id,
                })
                if sub.period_type=='day':
                    ds = (datetime.strptime(ds, '%Y-%m-%d') + relativedelta(days=sub.period_nbr)).strftime('%Y-%m-%d')
                if sub.period_type=='month':
                    ds = (datetime.strptime(ds, '%Y-%m-%d') + relativedelta(months=sub.period_nbr)).strftime('%Y-%m-%d')
                if sub.period_type=='year':
                    ds = (datetime.strptime(ds, '%Y-%m-%d') + relativedelta(years=sub.period_nbr)).strftime('%Y-%m-%d')
        self.write({'state':'running'})
        return True
    
class AccountSubscriptionLine(models.Model):
    _name = "account.subscription.line"
    _description = "Account Subscription Line"
    
    subscription_id = fields.Many2one('account.subscription', string='Subscription', required=True, select=True)
    date            = fields.Date(string='Date', required=True)
    move_id         = fields.Many2one('account.move', string='Entry')
    
    @api.multi
    def move_create(self):
        tocheck = {}
        all_moves = []
        obj_model = self.env['account.model']
        for line in self:
            data = {
                'date': line.date,
            }
            #move_ids = obj_model.generate([line.subscription_id.model_id.id], data)
            move_ids = line.subscription_id.model_id.generate(data)
            
            print "move_ids--->>", move_ids
            
            tocheck[line.subscription_id.id] = True
            line.write({'move_id':move_ids[0]})
            all_moves.extend(move_ids)
        #if tocheck:
        #    self.env['account.subscription'].check(tocheck.keys())
        return all_moves
    