# -*- coding: utf-8 -*-
"""
Cost Reports
============
- Total Pay
- Total Payroll Cost
- Deductions and Contributions
- Workers' Compensation
"""

from collections import defaultdict
from odoo import api, fields, models, _


class PayrollReportTotalPay(models.AbstractModel):
    """
    Total Pay Report
    Breakdown of pay by type per employee.
    """
    _name = 'payroll.report.total.pay'
    _inherit = 'payroll.report'
    _description = 'Total Pay Report'

    report_name = 'Total Pay'
    report_code = 'total_pay'

    def _get_columns(self):
        return [
            {'name': _('Name'), 'field': 'name', 'type': 'char', 'sortable': True},
            {'name': _('Regular Pay'), 'field': 'regular_pay', 'type': 'monetary', 'sortable': True},
            {'name': _('Stat Holiday Pay'), 'field': 'stat_holiday', 'type': 'monetary', 'sortable': True},
            {'name': _('Vacation Pay'), 'field': 'vacation_pay', 'type': 'monetary', 'sortable': True},
            {'name': _('Total'), 'field': 'total', 'type': 'monetary', 'sortable': True},
        ]

    def _get_lines(self, options):
        domain = self._get_domain(options)
        domain.append(('state', 'in', ['done', 'paid']))
        
        payslips = self.env['hr.payslip'].search(domain)
        
        # Aggregate by employee
        emp_data = defaultdict(lambda: {
            'regular_pay': 0,
            'stat_holiday': 0,
            'vacation_pay': 0,
            'total': 0,
        })
        
        for slip in payslips:
            if not slip.employee_id:
                continue
            
            emp_key = slip.employee_id.id
            emp_data[emp_key]['name'] = slip.employee_id.name or 'Unknown'
            
            if hasattr(slip, 'line_ids') and slip.line_ids:
                for line in slip.line_ids:
                    if hasattr(line, 'category_id') and line.category_id and hasattr(line.category_id, 'code'):
                        if line.category_id.code == 'BASIC':
                            emp_data[emp_key]['regular_pay'] += line.total or 0
                    if hasattr(line, 'code') and line.code:
                        if line.code == 'STAT_HOLIDAY':
                            emp_data[emp_key]['stat_holiday'] += line.total or 0
                        elif line.code == 'VACATION':
                            emp_data[emp_key]['vacation_pay'] += line.total or 0
            
            emp_data[emp_key]['total'] += getattr(slip, 'gross_wage', 0) or 0
        
        lines = []
        totals = defaultdict(float)
        
        for emp_id, data in emp_data.items():
            for key in ['regular_pay', 'stat_holiday', 'vacation_pay', 'total']:
                totals[key] += data[key]
            
            lines.append({
                'id': f'emp_{emp_id}',
                'name': data['name'],
                'values': {
                    'name': data['name'],
                    'regular_pay': data['regular_pay'],
                    'stat_holiday': data['stat_holiday'],
                    'vacation_pay': data['vacation_pay'],
                    'total': data['total'],
                },
                'level': 0,
            })
        
        # Sort by name
        lines.sort(key=lambda x: x['name'])
        
        # Total line
        if lines:
            lines.append({
                'id': 'total',
                'name': _('Total Pay'),
                'values': {
                    'name': _('Total Pay'),
                    'regular_pay': totals['regular_pay'],
                    'stat_holiday': totals['stat_holiday'],
                    'vacation_pay': totals['vacation_pay'],
                    'total': totals['total'],
                },
                'level': -1,
                'class': 'o_payroll_report_total fw-bold bg-success text-white',
            })
        
        return lines


class PayrollReportTotalCost(models.AbstractModel):
    """
    Total Payroll Cost Report
    Summary of all payroll costs.
    """
    _name = 'payroll.report.total.cost'
    _inherit = 'payroll.report'
    _description = 'Total Payroll Cost Report'

    report_name = 'Total Payroll Cost'
    report_code = 'total_cost'
    filter_employee = False

    def _get_columns(self):
        return [
            {'name': _('Item'), 'field': 'item', 'type': 'char', 'sortable': False},
            {'name': _('Amount'), 'field': 'amount', 'type': 'monetary', 'sortable': True},
        ]

    def _get_lines(self, options):
        domain = [
            ('state', 'in', ['done', 'paid']),
            ('company_id', '=', self.env.company.id),
        ]
        date_from = options.get('date', {}).get('date_from')
        date_to = options.get('date', {}).get('date_to')
        if date_from:
            domain.append(('date_from', '>=', date_from))
        if date_to:
            domain.append(('date_to', '<=', date_to))
        
        payslips = self.env['hr.payslip'].search(domain)
        
        # Calculate totals - safely handle missing fields
        paycheque_wages = 0
        non_paycheque = 0  # Reimbursements, etc.
        reimbursements = 0
        
        ei_employer = 0
        cpp_employer = 0
        cpp2_employer = 0
        
        for slip in payslips:
            paycheque_wages += getattr(slip, 'gross_wage', 0) or 0
            ei_employer += getattr(slip, 'employer_ei', 0) or 0
            cpp_employer += getattr(slip, 'employer_cpp', 0) or 0
            cpp2_employer += getattr(slip, 'employer_cpp2', 0) or 0
        
        total_employer_taxes = ei_employer + cpp_employer + cpp2_employer
        total_pay = paycheque_wages + non_paycheque + reimbursements
        total_cost = total_pay + total_employer_taxes
        
        lines = [
            # Total Pay Section
            {
                'id': 'total_pay_header',
                'name': _('Total Pay'),
                'values': {'item': _('Total Pay'), 'amount': ''},
                'level': -1,
                'class': 'fw-bold',
            },
            {
                'id': 'paycheque_wages',
                'name': _('Paycheque Wages'),
                'values': {'item': _('  Paycheque Wages'), 'amount': paycheque_wages},
                'level': 0,
            },
            {
                'id': 'non_paycheque',
                'name': _('Non-paycheque Wages'),
                'values': {'item': _('  Non-paycheque Wages'), 'amount': non_paycheque},
                'level': 0,
            },
            {
                'id': 'reimbursements',
                'name': _('Reimbursements'),
                'values': {'item': _('  Reimbursements'), 'amount': reimbursements},
                'level': 0,
            },
            {
                'id': 'subtotal_pay',
                'name': _('Subtotal'),
                'values': {'item': _('Subtotal'), 'amount': total_pay},
                'level': 0,
                'class': 'fw-bold',
            },
            # Company Contributions Section
            {
                'id': 'contributions_header',
                'name': _('Company Contributions'),
                'values': {'item': _('Company Contributions'), 'amount': ''},
                'level': -1,
                'class': 'fw-bold',
            },
            {
                'id': 'subtotal_contributions',
                'name': _('Subtotal'),
                'values': {'item': _('Subtotal'), 'amount': 0},
                'level': 0,
                'class': 'fw-bold',
            },
            # Employer Taxes Section
            {
                'id': 'employer_taxes_header',
                'name': _('Employer Taxes'),
                'values': {'item': _('Employer Taxes'), 'amount': ''},
                'level': -1,
                'class': 'fw-bold',
            },
            {
                'id': 'ei_employer',
                'name': _('Employment Insurance Employer'),
                'values': {'item': _('  Employment Insurance Employer'), 'amount': ei_employer},
                'level': 0,
            },
            {
                'id': 'cpp_employer',
                'name': _('Canada Pension Plan Employer'),
                'values': {'item': _('  Canada Pension Plan Employer'), 'amount': cpp_employer},
                'level': 0,
            },
            {
                'id': 'cpp2_employer',
                'name': _('Second Canada Pension Plan Employer'),
                'values': {'item': _('  Second Canada Pension Plan Employer'), 'amount': cpp2_employer},
                'level': 0,
            },
            {
                'id': 'subtotal_employer',
                'name': _('Subtotal'),
                'values': {'item': _('Subtotal'), 'amount': total_employer_taxes},
                'level': 0,
                'class': 'fw-bold',
            },
            # Grand Total
            {
                'id': 'total_cost',
                'name': _('Total Payroll Cost'),
                'values': {'item': _('Total Payroll Cost'), 'amount': total_cost},
                'level': -1,
                'class': 'o_payroll_report_total fw-bold bg-dark text-white',
            },
        ]
        
        return lines


class PayrollReportDeductions(models.AbstractModel):
    """
    Deductions and Contributions Report
    """
    _name = 'payroll.report.deductions'
    _inherit = 'payroll.report'
    _description = 'Deductions and Contributions Report'

    report_name = 'Deductions and Contributions'
    report_code = 'deductions'
    filter_employee = False

    def _get_columns(self):
        return [
            {'name': _('Description'), 'field': 'description', 'type': 'char', 'sortable': True},
            {'name': _('Type'), 'field': 'type', 'type': 'char', 'sortable': True},
            {'name': _('Employee Deductions'), 'field': 'employee_deductions', 'type': 'monetary', 'sortable': True},
            {'name': _('Company Contributions'), 'field': 'company_contributions', 'type': 'monetary', 'sortable': True},
            {'name': _('Plan Total'), 'field': 'plan_total', 'type': 'monetary', 'sortable': True},
        ]

    def _get_lines(self, options):
        domain = [
            ('state', 'in', ['done', 'paid']),
            ('company_id', '=', self.env.company.id),
        ]
        date_from = options.get('date', {}).get('date_from')
        date_to = options.get('date', {}).get('date_to')
        if date_from:
            domain.append(('date_from', '>=', date_from))
        if date_to:
            domain.append(('date_to', '<=', date_to))
        
        payslips = self.env['hr.payslip'].search(domain)
        
        # Aggregate deductions
        deduction_data = defaultdict(lambda: {'employee': 0, 'company': 0})
        
        deduction_codes = {
            'CPP': {'name': 'Canada Pension Plan', 'type': 'Tax', 'employer_code': 'CPP_ER'},
            'CPP2': {'name': 'Second Canada Pension Plan', 'type': 'Tax', 'employer_code': 'CPP2_ER'},
            'EI': {'name': 'Employment Insurance', 'type': 'Tax', 'employer_code': 'EI_ER'},
        }
        
        for slip in payslips:
            if not hasattr(slip, 'line_ids') or not slip.line_ids:
                continue
            for line in slip.line_ids:
                if not hasattr(line, 'code') or not line.code:
                    continue
                if line.code in deduction_codes:
                    deduction_data[line.code]['employee'] += abs(line.total or 0)
                elif line.code.endswith('_ER'):
                    base_code = line.code[:-3]
                    if base_code in deduction_codes:
                        deduction_data[base_code]['company'] += abs(line.total or 0)
        
        lines = []
        for code, info in deduction_codes.items():
            data = deduction_data[code]
            total = data['employee'] + data['company']
            
            lines.append({
                'id': f'ded_{code}',
                'name': info['name'],
                'values': {
                    'description': info['name'],
                    'type': info['type'],
                    'employee_deductions': data['employee'],
                    'company_contributions': data['company'],
                    'plan_total': total,
                },
                'level': 0,
            })
        
        return lines


class PayrollReportWorkersComp(models.AbstractModel):
    """
    Workers' Compensation Report
    """
    _name = 'payroll.report.workers.comp'
    _inherit = 'payroll.report'
    _description = 'Workers Compensation Report'

    report_name = "Workers' Compensation"
    report_code = 'workers_comp'
    filter_employee = False

    def _get_columns(self):
        return [
            {'name': _('Province'), 'field': 'province', 'type': 'char', 'sortable': True},
            {'name': _("Workers' Comp Class"), 'field': 'wc_class', 'type': 'char', 'sortable': True},
            {'name': _('Premium Wage Paid'), 'field': 'premium_wage', 'type': 'monetary', 'sortable': True},
            {'name': _('Tips Paid'), 'field': 'tips_paid', 'type': 'monetary', 'sortable': True},
            {'name': _('Employee Taxes Paid by Employer'), 'field': 'emp_taxes_employer', 'type': 'monetary', 'sortable': True},
            {'name': _('Wages Paid'), 'field': 'wages_paid', 'type': 'monetary', 'sortable': True},
        ]

    def _get_lines(self, options):
        domain = [
            ('state', 'in', ['done', 'paid']),
            ('company_id', '=', self.env.company.id),
        ]
        date_from = options.get('date', {}).get('date_from')
        date_to = options.get('date', {}).get('date_to')
        if date_from:
            domain.append(('date_from', '>=', date_from))
        if date_to:
            domain.append(('date_to', '<=', date_to))
        
        payslips = self.env['hr.payslip'].search(domain)
        
        # Group by province
        province_data = defaultdict(lambda: {'wages': 0, 'premium': 0, 'tips': 0, 'emp_taxes': 0})
        
        for slip in payslips:
            if not slip.employee_id:
                continue
            
            province = 'ON'  # Default, would get from employee address
            if hasattr(slip.employee_id, 'province_of_employment'):
                province = getattr(slip.employee_id, 'province_of_employment', None) or 'ON'
            
            province_data[province]['wages'] += getattr(slip, 'gross_wage', 0) or 0
        
        lines = []
        total_wages = 0
        
        for province, data in province_data.items():
            total_wages += data['wages']
            lines.append({
                'id': f'prov_{province}',
                'name': province,
                'values': {
                    'province': province,
                    'wc_class': 'No Name Specified',
                    'premium_wage': data['premium'],
                    'tips_paid': data['tips'],
                    'emp_taxes_employer': data['emp_taxes'],
                    'wages_paid': data['wages'],
                },
                'level': 0,
            })
        
        # Total
        if lines:
            lines.append({
                'id': 'total',
                'name': _('Total'),
                'values': {
                    'province': _('Total'),
                    'wc_class': '',
                    'premium_wage': 0,
                    'tips_paid': 0,
                    'emp_taxes_employer': 0,
                    'wages_paid': total_wages,
                },
                'level': -1,
                'class': 'o_payroll_report_total fw-bold bg-success text-white',
            })
        
        return lines
