import calendar
import datetime
import uuid
from pyramid.response import Response
from pyramid.security import authenticated_userid
from pyramid.view import view_config
from sqlalchemy import or_
import transaction
from brewman.models import DBSession
from brewman.models.auth import User
from brewman.models.master import AttendanceType, Employee, Ledger
from brewman.models.validation_exception import ValidationError, TryCatchFunction
from brewman.models.voucher import Attendance, Voucher, VoucherType, Journal
from brewman.views.attendance import daterange
from brewman.views.services.session import  session_period_start, session_period_finish, get_last_day, get_first_day

__author__ = 'tanshu'

@view_config(route_name='attendance_report', renderer='csv', permission='Attendance')
def get_report(request):
    start_date = request.GET.get('StartDate', session_period_start(request))
    finish_date = request.GET.get('FinishDate', session_period_finish(request))
    start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y')
    finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y')
    header, report = attendance_record(start_date, finish_date)
    return {'header': header, 'rows': report, 'filename': 'Attendance Record.csv'}


def attendance_record(start_date, finish_date):
    report = []
    header = ["Code", "Name", "Designation", "Department", "Salary", "SC Points"]
    for date in daterange(start_date, finish_date, inclusive=True):
        header.append(date.strftime('%d-%b'))

    not_set = AttendanceType.by_id(0)
    employees = DBSession().query(Employee)\
    .filter(Employee.joining_date <= finish_date)\
    .filter(or_(Employee.is_active, Employee.leaving_date >= start_date))\
    .order_by(Employee.costcenter_id).order_by(Employee.designation).order_by(Employee.name).all()
    for employee in employees:
        row_display = [employee.code, employee.name, employee.designation, employee.costcenter.name, employee.salary,
                       employee.service_points]
        row_value = ['', '', '', '', employee.salary, employee.service_points]
        for date in daterange(start_date, finish_date, inclusive=True):
            att = DBSession.query(Attendance)\
            .filter(Attendance.employee_id == employee.id)\
            .filter(Attendance.date == date)\
            .filter(Attendance.is_valid == True)\
            .first()
            att = not_set if att is None else AttendanceType.by_id(att.attendance_type)
            row_display.append(att.name)
            row_value.append(att.value)
        report.extend([tuple(row_display), tuple(row_value)])
    return header, report


@view_config(request_method='POST', route_name='api_credit_salary', renderer='json', permission='Attendance')
@TryCatchFunction
def credit_salary(request):
    user = User.by_id(uuid.UUID(authenticated_userid(request)))
    month = datetime.datetime.strptime(request.json_body['Month'], '%d-%b-%Y')

    start_date = get_first_day(month)
    finish_date = get_last_day(month)
    voucher = Voucher(date=finish_date, narration='Auto Generated Salary Entry', user_id=user.id,
        type=VoucherType.by_name('Journal'), posted=True, poster_id=user.id)
    DBSession.add(voucher)
    for item in salary_journals(start_date, finish_date):
        voucher.journals.append(item)
        DBSession.add(item)
    transaction.commit()
    return {'message': 'Salary Entry created'}


def salary_journals(start_date, finish_date):
    days = calendar.monthrange(start_date.year, start_date.month)[1]
    finish_date = finish_date + datetime.timedelta(1)
    amount = 0
    journals = []
    employees = DBSession().query(Employee)\
    .filter(Employee.joining_date <= finish_date)\
    .filter(or_(Employee.is_active, Employee.leaving_date >= start_date))\
    .order_by(Employee.costcenter_id).order_by(Employee.designation).order_by(Employee.name).all()
    for employee in employees:
        att = DBSession.query(Attendance)\
        .filter(Attendance.employee_id == employee.id)\
        .filter(Attendance.date >= start_date)\
        .filter(Attendance.date < finish_date)\
        .filter(Attendance.is_valid == True)\
        .all()
        att = sum(map(lambda x: AttendanceType.by_id(x.attendance_type).value, att))
        att = round(att * employee.salary / days)
        amount += att
        journals.append(Journal(amount=att, debit=-1, ledger_id=employee.id, cost_center_id=employee.costcenter_id))
    salary = Ledger.salary()
    salary = Ledger.by_id(uuid.UUID(salary['LedgerID']))
    journals.append(Journal(amount=amount, debit=1, ledger_id=salary.id, cost_center_id=salary.costcenter_id))
    return journals

