# -*- coding: utf-8 -*-
"""
Summary Reports
===============
- Payroll Summary
- Payroll Summary by Employee
"""

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


class PayrollReportSummary(models.AbstractModel):
    """
    Payroll Summary Report
    Per pay date summary with all payroll components.
    """
    _name = 'payroll.report.summary'
    _inherit = 'payroll.report'
    _description = 'Payroll Summary Report'

    report_name = 'Payroll Summary'
    report_code = 'payroll_summary'

    def _get_columns(self):
        return [
            {'name': _('Pay Date'), 'field': 'pay_date', 'type': 'date', 'sortable': True},
            {'name': _('Name'), 'field': 'name', 'type': 'char', 'sortable': True},
            {'name': _('Hours'), 'field': 'hours', 'type': 'float', 'sortable': True},
            {'name': _('Gross Pay'), 'field': 'gross_pay', 'type': 'monetary', 'sortable': True},
            {'name': _('Pretax Deductions'), 'field': 'pretax_deductions', 'type': 'monetary', 'sortable': False},
            {'name': _('Other Pay'), 'field': 'other_pay', 'type': 'monetary', 'sortable': False},
            {'name': _('Employee Taxes'), 'field': 'employee_taxes', 'type': 'monetary', 'sortable': True},
            {'name': _('Aftertax Deductions'), 'field': 'aftertax_deductions', 'type': 'monetary', 'sortable': False},
            {'name': _('Net Pay'), 'field': 'net_pay', 'type': 'monetary', 'sortable': True},
            {'name': _('Employer Taxes'), 'field': 'employer_taxes', 'type': 'monetary', 'sortable': True},
            {'name': _('Company Contributions'), 'field': 'company_contributions', 'type': 'monetary', 'sortable': False},
            {'name': _('Total Payroll Cost'), 'field': 'total_cost', '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, order='date_to desc, employee_id')
        
        lines = []
        totals = defaultdict(float)
        
        for slip in payslips:
            if not slip.employee_id:
                continue
            
            hours = 0
            if hasattr(slip, 'worked_days_line_ids') and slip.worked_days_line_ids:
                hours = sum(slip.worked_days_line_ids.mapped('number_of_hours')) or 0
            
            employee_taxes = getattr(slip, 'total_employee_deductions', 0) or 0
            employer_taxes = getattr(slip, 'total_employer_cost', 0) or 0
            gross_wage = getattr(slip, 'gross_wage', 0) or 0
            net_wage = getattr(slip, 'net_wage', 0) or 0
            total_cost = gross_wage + employer_taxes
            
            values = {
                'pay_date': slip.date_to or '',
                'name': slip.employee_id.name or 'Unknown',
                'hours': hours,
                'gross_pay': gross_wage,
                'pretax_deductions': 0,
                'other_pay': 0,
                'employee_taxes': employee_taxes,
                'aftertax_deductions': 0,
                'net_pay': net_wage,
                'employer_taxes': employer_taxes,
                'company_contributions': 0,
                'total_cost': total_cost,
            }
            
            # Accumulate totals
            for key in ['hours', 'gross_pay', 'employee_taxes', 'net_pay', 'employer_taxes', 'total_cost']:
                totals[key] += values[key]
            
            lines.append({
                'id': f'summary_{slip.id}',
                'name': slip.employee_id.name or 'Unknown',
                'values': values,
                'level': 0,
                'model': 'hr.payslip',
                'res_id': slip.id,
            })
        
        # Total line
        if lines:
            lines.insert(0, {
                'id': 'total',
                'name': _('Total'),
                'values': {
                    'pay_date': '',
                    'name': _('Total'),
                    'hours': totals['hours'],
                    'gross_pay': totals['gross_pay'],
                    'pretax_deductions': 0,
                    'other_pay': 0,
                    'employee_taxes': totals['employee_taxes'],
                    'aftertax_deductions': 0,
                    'net_pay': totals['net_pay'],
                    'employer_taxes': totals['employer_taxes'],
                    'company_contributions': 0,
                    'total_cost': totals['total_cost'],
                },
                'level': -1,
                'class': 'o_payroll_report_total fw-bold bg-light',
            })
        
        return lines


class PayrollReportSummaryByEmployee(models.AbstractModel):
    """
    Payroll Summary by Employee Report
    Pivot-style with employees as columns, pay types as rows.
    """
    _name = 'payroll.report.summary.by.employee'
    _inherit = 'payroll.report'
    _description = 'Payroll Summary by Employee Report'

    report_name = 'Payroll Summary by Employee'
    report_code = 'payroll_summary_employee'

    def _get_columns(self):
        # Dynamic columns based on employees in date range
        # Base columns first
        return [
            {'name': _('Payroll'), 'field': 'payroll_item', 'type': 'char', 'sortable': False},
            {'name': _('Total'), 'field': 'total', 'type': 'monetary', 'sortable': True},
            # Employee columns will be added dynamically
        ]

    def _get_dynamic_columns(self, options):
        """Get columns including employee names."""
        date_from = options.get('date', {}).get('date_from')
        date_to = options.get('date', {}).get('date_to')
        
        domain = [
            ('state', 'in', ['done', 'paid']),
            ('company_id', '=', self.env.company.id),
        ]
        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)
        employees = payslips.mapped('employee_id')
        
        columns = [
            {'name': _('Payroll'), 'field': 'payroll_item', 'type': 'char', 'sortable': False},
            {'name': _('Total'), 'field': 'total', 'type': 'monetary', 'sortable': True},
        ]
        
        for emp in employees.sorted('name'):
            columns.append({
                'name': emp.name,
                'field': f'emp_{emp.id}',
                'type': 'monetary',
                'sortable': True,
            })
        
        return columns, employees

    def _get_lines(self, options):
        date_from = options.get('date', {}).get('date_from')
        date_to = options.get('date', {}).get('date_to')
        
        domain = [
            ('state', 'in', ['done', 'paid']),
            ('company_id', '=', self.env.company.id),
        ]
        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)
        employees = payslips.mapped('employee_id').sorted('name')
        
        # Initialize data structure
        rows = {
            'hours': {'name': _('Hours'), 'is_header': True, 'totals': defaultdict(float)},
            'regular_pay_hrs': {'name': _('Regular Pay'), 'parent': 'hours', 'totals': defaultdict(float)},
            'stat_holiday_hrs': {'name': _('Stat Holiday Pay'), 'parent': 'hours', 'totals': defaultdict(float)},
            'gross_pay': {'name': _('Gross Pay'), 'is_header': True, 'totals': defaultdict(float)},
            'regular_pay': {'name': _('Regular Pay'), 'parent': 'gross_pay', 'totals': defaultdict(float)},
            'stat_holiday_pay': {'name': _('Stat Holiday Pay'), 'parent': 'gross_pay', 'totals': defaultdict(float)},
            'vacation_pay': {'name': _('Vacation Pay'), 'parent': 'gross_pay', 'totals': defaultdict(float)},
            'adjusted_gross': {'name': _('Adjusted Gross'), 'is_subtotal': True, 'totals': defaultdict(float)},
            'employee_taxes': {'name': _('Employee Taxes & Deductions'), 'is_header': True, 'totals': defaultdict(float)},
            'income_tax': {'name': _('Income Tax'), 'parent': 'employee_taxes', 'totals': defaultdict(float)},
            'ei': {'name': _('Employment Insurance'), 'parent': 'employee_taxes', 'totals': defaultdict(float)},
            'cpp': {'name': _('Canada Pension Plan'), 'parent': 'employee_taxes', 'totals': defaultdict(float)},
            'net_pay': {'name': _('Net Pay'), 'is_header': True, 'totals': defaultdict(float)},
            'employer_taxes': {'name': _('Employer Taxes & Contributions'), 'is_header': True, 'totals': defaultdict(float)},
            'ei_employer': {'name': _('Employment Insurance Employer'), 'parent': 'employer_taxes', 'totals': defaultdict(float)},
            'cpp_employer': {'name': _('Canada Pension Plan Employer'), 'parent': 'employer_taxes', 'totals': defaultdict(float)},
            'total_cost': {'name': _('Total Payroll Cost'), 'is_total': True, 'totals': defaultdict(float)},
        }
        
        # Aggregate data by employee
        for slip in payslips:
            if not slip.employee_id:
                continue
            
            emp_key = f'emp_{slip.employee_id.id}'
            
            # Hours
            hours = 0
            if hasattr(slip, 'worked_days_line_ids') and slip.worked_days_line_ids:
                hours = sum(slip.worked_days_line_ids.mapped('number_of_hours')) or 0
            rows['hours']['totals'][emp_key] += hours
            rows['regular_pay_hrs']['totals'][emp_key] += hours
            
            # Gross
            gross_wage = getattr(slip, 'gross_wage', 0) or 0
            rows['gross_pay']['totals'][emp_key] += gross_wage
            rows['regular_pay']['totals'][emp_key] += gross_wage
            rows['adjusted_gross']['totals'][emp_key] += gross_wage
            
            # Employee taxes
            rows['employee_taxes']['totals'][emp_key] += getattr(slip, 'total_employee_deductions', 0) or 0
            rows['income_tax']['totals'][emp_key] += getattr(slip, 'employee_income_tax', 0) or 0
            rows['ei']['totals'][emp_key] += getattr(slip, 'employee_ei', 0) or 0
            rows['cpp']['totals'][emp_key] += getattr(slip, 'employee_cpp', 0) or 0
            
            # Net
            rows['net_pay']['totals'][emp_key] += getattr(slip, 'net_wage', 0) or 0
            
            # Employer
            total_employer_cost = getattr(slip, 'total_employer_cost', 0) or 0
            rows['employer_taxes']['totals'][emp_key] += total_employer_cost
            rows['ei_employer']['totals'][emp_key] += getattr(slip, 'employer_ei', 0) or 0
            rows['cpp_employer']['totals'][emp_key] += getattr(slip, 'employer_cpp', 0) or 0
            
            # Total cost
            rows['total_cost']['totals'][emp_key] += gross_wage + total_employer_cost
        
        # Build lines
        lines = []
        for row_key, row_data in rows.items():
            values = {'payroll_item': row_data['name']}
            
            # Calculate total
            total = sum(row_data['totals'].values())
            values['total'] = total
            
            # Add employee columns
            for emp in employees:
                emp_field = f'emp_{emp.id}'
                values[emp_field] = row_data['totals'].get(emp_field, 0)
            
            level = 0
            css_class = ''
            if row_data.get('is_header'):
                level = -1
                css_class = 'fw-bold'
            elif row_data.get('parent'):
                level = 1
                values['payroll_item'] = f"  {row_data['name']}"
            elif row_data.get('is_subtotal'):
                css_class = 'fw-bold'
            elif row_data.get('is_total'):
                level = -1
                css_class = 'fw-bold bg-primary text-white'
            
            lines.append({
                'id': row_key,
                'name': row_data['name'],
                'values': values,
                'level': level,
                'class': css_class,
            })
        
        return lines
