import datetime
import uuid
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.master import AttendanceType, Employee
from brewman.models.validation_exception import ValidationError, TryCatchFunction
from brewman.models.voucher import Attendance
from brewman.views.fingerprint import get_prints
from brewman.views.services.session import session_period_start, session_period_finish, session_current_date

__author__ = 'tanshu'

@view_config(request_method='GET', route_name='attendance_date', renderer='brewman:templates/angular_base.mako',
    permission='Attendance')
@view_config(request_method='GET', route_name='attendance', renderer='brewman:templates/angular_base.mako',
    permission='Attendance')
@view_config(request_method='GET', route_name='employee_attendance_id', renderer='brewman:templates/angular_base.mako',
    permission='Attendance')
@view_config(request_method='GET', route_name='employee_attendance', renderer='brewman:templates/angular_base.mako',
    permission='Attendance')
def html(request):
    return {}


@view_config(request_method='GET', route_name='api_attendance_types', renderer='json', permission='Authenticated')
def show_list(request):
    list = AttendanceType.list()
    attendance_types = []
    for item in list:
        attendance_types.append({'AttendanceTypeID': item.id, 'Name': item.name, 'Value': item.value})
    return attendance_types


@view_config(request_method='GET', route_name='api_attendance', renderer='json', permission='Attendance')
def attendance_blank(request):
    return {'Date': session_current_date(request), 'Body': []}


@view_config(request_method='GET', route_name='api_attendance_date', renderer='json', permission='Attendance')
def attendance_date(request):
    date = request.matchdict.get('date', None)
    return attendance_date_report(date)


def attendance_date_report(date):
    report = {'Date': date, 'Body': []}
    date = datetime.datetime.strptime(date, '%d-%b-%Y')
    employees = DBSession().query(Employee)\
    .filter(Employee.joining_date <= date)\
    .filter(or_(Employee.is_active, Employee.leaving_date >= date))\
    .order_by(Employee.costcenter_id).order_by(Employee.designation).order_by(Employee.name).all()
    for item in employees:
        att = DBSession().query(Attendance).filter(Attendance.employee_id == item.id).filter(
            Attendance.date == date).filter(Attendance.is_valid == True).first()
        att = 0 if att is None else att.attendance_type

        prints, hours, worked = get_prints(item.id, date)
        report['Body'].append({'id': item.id, 'Code': item.code, 'Name': item.name, 'Designation': item.designation,
                               'Department': item.costcenter.name, 'AttendanceTypeID': att, 'Prints': prints,
                               'Hours': hours, 'Worked': worked})
    return report


@view_config(request_method='POST', route_name='api_attendance_date', renderer='json', permission='Attendance')
@TryCatchFunction
def save(request):
    user_id = uuid.UUID(authenticated_userid(request))
    date = request.matchdict.get('date', None)
    date_object = datetime.datetime.strptime(date, '%d-%b-%Y')

    for item in request.json_body['Body']:
        employee_id = uuid.UUID(item['id'])
        attendance_type = item['AttendanceTypeID']
        if attendance_type != 0:
            attendance = Attendance(employee_id=employee_id, date=date_object, attendance_type=attendance_type,
                user_id=user_id)
            attendance.create()
    transaction.commit()
    return attendance_date_report(date)


@view_config(request_method='GET', route_name='api_employee_attendance', renderer='json', permission='Attendance')
def employee_attendance_blank(request):
    return {'StartDate': session_period_start(request),
            'FinishDate': session_period_finish(request), 'Employee': None, 'Body': []}


@view_config(request_method='GET', route_name='api_employee_attendance_id', renderer='json', permission='Attendance')
def employee_attendance_report(request):
    employee = Employee.by_id(uuid.UUID(request.matchdict['id']))
    if employee is None:
        raise ValidationError('Employee id is wrong')
    start_date = request.GET.get('StartDate', session_period_start(request))
    finish_date = request.GET.get('FinishDate', session_period_finish(request))
    info = {'StartDate': start_date, 'FinishDate': finish_date,
            'Employee': {'LedgerID': employee.id, 'Name': employee.name}}
    start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y')
    finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y')
    start_date = employee.joining_date if employee.joining_date > start_date else start_date
    finish_date = employee.leaving_date if not employee.is_active and employee.leaving_date < finish_date else finish_date
    info['Body'] = employee_attendance(employee, start_date, finish_date)
    return info


def employee_attendance(employee, start_date, finish_date):
    if not isinstance(start_date, datetime.datetime):
        start_date = datetime.datetime.strptime(start_date, '%d-%b-%Y')
    if not isinstance(finish_date, datetime.datetime):
        finish_date = datetime.datetime.strptime(finish_date, '%d-%b-%Y')
    list = []
    for item in daterange(start_date, finish_date, inclusive=True):
        att = DBSession.query(Attendance)\
        .filter(Attendance.employee_id == employee.id)\
        .filter(Attendance.date == item)\
        .filter(Attendance.is_valid == True)\
        .first()
        att = 0 if att is None else att.attendance_type
        prints, hours, worked = get_prints(employee.id, item)
        list.append({'Date': item.strftime('%d-%b-%Y'), 'AttendanceTypeID': att, 'Prints': prints, 'Hours': hours,
                     'Worked': worked})
    return list


@view_config(request_method='POST', route_name='api_employee_attendance_id', renderer='json', permission='Attendance')
@TryCatchFunction
def save_employee_attendance(request):
    start_date = None
    finish_date = None
    user_id = uuid.UUID(authenticated_userid(request))
    employee = Employee.by_id(uuid.UUID(request.matchdict['id']))
    for item in request.json_body['Body']:
        if start_date is None:
            start_date = item['Date']
        finish_date = item['Date']

        attendance_type = item['AttendanceTypeID']
        if attendance_type != 0:
            date = datetime.datetime.strptime(item['Date'], '%d-%b-%Y')
            attendance = Attendance(employee_id=employee.id, date=date, attendance_type=attendance_type,
                user_id=user_id)
            attendance.create()
    transaction.commit()
    return {'StartDate': start_date, 'FinishDate': finish_date,
            'Employee': {'LedgerID': employee.id, 'Name': employee.name},
            'Body': employee_attendance(employee, start_date, finish_date)}


def daterange(start, stop, step=datetime.timedelta(days=1), inclusive=False):
    # inclusive=False to behave like range by default
    if step.days > 0:
        while start < stop:
            yield start
            start = start + step
            # not +=! don't modify object passed in if it's mutable
            # since this function is not restricted to
            # only types from datetime module
    elif step.days < 0:
        while start > stop:
            yield start
            start = start + step
    if inclusive and start == stop:
        yield start