# -*- coding: utf-8 -*-

from odoo import api, fields, models, _
from odoo.exceptions import UserError
from dateutil.relativedelta import relativedelta


class RunPayrollWizard(models.TransientModel):
    _name = 'run.payroll.wizard'
    _description = 'Run Payroll'
    _rec_name = 'display_name'
    
    display_name = fields.Char(compute='_compute_display_name')
    
    @api.depends('pay_schedule', 'date_start', 'date_end')
    def _compute_display_name(self):
        schedule_labels = {
            'weekly': 'Weekly',
            'biweekly': 'Bi-Weekly',
            'semi_monthly': 'Semi-Monthly',
            'monthly': 'Monthly',
        }
        for wizard in self:
            schedule = schedule_labels.get(wizard.pay_schedule, 'Bi-Weekly')
            wizard.display_name = f"Run Payroll: {schedule}"

    # === Wizard State ===
    state = fields.Selection([
        ('entry', 'Enter Payroll'),
        ('preview', 'Preview Payroll'),
    ], string='State', default='entry')

    # === Company & Schedule ===
    company_id = fields.Many2one(
        'res.company',
        string='Company',
        required=True,
        default=lambda self: self.env.company,
    )
    
    # === Pay Period Selection (QuickBooks-like dropdown) ===
    pay_period_id = fields.Many2one(
        'payroll.pay.period',
        string='Pay Period',
        domain="[('company_id', '=', company_id)]",
    )
    pay_schedule = fields.Selection([
        ('weekly', 'Weekly'),
        ('biweekly', 'Bi-Weekly'),
        ('semi_monthly', 'Semi-Monthly'),
        ('monthly', 'Monthly'),
    ], string='Pay Schedule', required=True, default='biweekly')
    
    # === Chart of Accounts (for journal entries) ===
    bank_account_id = fields.Many2one(
        'account.account',
        string='Funding Account',
        domain="[('account_type', 'in', ['asset_cash', 'liability_credit_card'])]",
        help='Bank or credit card account to fund payroll',
    )
    
    # === Preview Summary Fields ===
    total_payroll_cost = fields.Monetary(
        string='Total Payroll Cost',
        currency_field='currency_id',
        compute='_compute_preview_totals',
    )
    change_from_last = fields.Float(
        string='Change from Last (%)',
        compute='_compute_preview_totals',
    )
    
    date_start = fields.Date(
        string='Period Start',
        required=True,
        default=lambda self: self._default_date_start(),
    )
    date_end = fields.Date(
        string='Period End',
        required=True,
        default=lambda self: self._default_date_end(),
    )
    pay_date = fields.Date(
        string='Pay Date',
        required=True,
        default=lambda self: fields.Date.context_today(self) + relativedelta(days=7),
    )

    # Period display name for dropdown
    period_display = fields.Char(
        string='Period',
        compute='_compute_period_display',
    )
    
    # === Employee Payroll Entries (QuickBooks-like grid) ===
    entry_ids = fields.One2many(
        'payroll.entry',
        'wizard_id',
        string='Payroll Entries',
    )
    
    # Summary totals
    total_regular_hours = fields.Float(
        string='Total Regular Hours',
        compute='_compute_totals',
    )
    total_hours = fields.Float(
        string='Total Hours',
        compute='_compute_totals',
    )
    total_gross_pay = fields.Monetary(
        string='Total Gross Pay',
        currency_field='currency_id',
        compute='_compute_totals',
    )
    total_net_pay = fields.Monetary(
        string='Total Net Pay',
        currency_field='currency_id',
        compute='_compute_totals',
    )
    total_employee_taxes = fields.Monetary(
        string='Total Employee Taxes',
        currency_field='currency_id',
        compute='_compute_totals',
    )
    total_employer_taxes = fields.Monetary(
        string='Total Employer Taxes',
        currency_field='currency_id',
        compute='_compute_totals',
    )
    employee_count = fields.Integer(
        string='Employees',
        compute='_compute_totals',
    )
    selected_count = fields.Integer(
        string='Selected',
        compute='_compute_totals',
    )
    
    currency_id = fields.Many2one(
        'res.currency',
        string='Currency',
        default=lambda self: self.env.company.currency_id,
    )

    # === Generated Payslips ===
    payslip_run_id = fields.Many2one(
        'hr.payslip.run',
        string='Payslip Batch',
        readonly=True,
    )
    payslip_count = fields.Integer(
        string='Payslips Generated',
        compute='_compute_payslip_count',
    )

    # Available periods for dropdown
    available_period_ids = fields.Many2many(
        'payroll.pay.period',
        string='Available Periods',
        compute='_compute_available_periods',
    )

    def _default_date_start(self):
        """Default to start of current pay period"""
        today = fields.Date.context_today(self)
        # Default to start of current bi-weekly period (Monday)
        return today - relativedelta(days=today.weekday())

    def _default_date_end(self):
        """Default to end of current pay period"""
        today = fields.Date.context_today(self)
        start = today - relativedelta(days=today.weekday())
        return start + relativedelta(days=13)

    @api.depends('date_start', 'date_end')
    def _compute_period_display(self):
        for wizard in self:
            if wizard.date_start and wizard.date_end:
                wizard.period_display = f"{wizard.date_start.strftime('%m.%d.%Y')} to {wizard.date_end.strftime('%m.%d.%Y')}"
            else:
                wizard.period_display = ''

    @api.depends('company_id', 'pay_schedule')
    def _compute_available_periods(self):
        today = fields.Date.context_today(self)
        six_months_ago = today - relativedelta(months=6)
        
        for wizard in self:
            # Get periods from last 6 months plus future periods
            periods = self.env['payroll.pay.period'].search([
                ('company_id', '=', wizard.company_id.id),
                ('schedule_type', '=', wizard.pay_schedule),
                '|',
                ('date_start', '>=', six_months_ago),  # Past 6 months
                ('date_end', '>=', today),  # Current and future
            ], order='date_start asc')  # Sort ascending so current is near top
            wizard.available_period_ids = periods

    @api.depends('entry_ids', 'entry_ids.regular_hours', 'entry_ids.total_hours', 
                 'entry_ids.gross_pay', 'entry_ids.net_pay', 
                 'entry_ids.total_employee_tax', 'entry_ids.total_employer_tax')
    def _compute_totals(self):
        for wizard in self:
            wizard.total_regular_hours = sum(wizard.entry_ids.mapped('regular_hours'))
            wizard.total_hours = sum(wizard.entry_ids.mapped('total_hours'))
            wizard.total_gross_pay = sum(wizard.entry_ids.mapped('gross_pay'))
            wizard.total_net_pay = sum(wizard.entry_ids.mapped('net_pay'))
            wizard.total_employee_taxes = sum(wizard.entry_ids.mapped('total_employee_tax'))
            wizard.total_employer_taxes = sum(wizard.entry_ids.mapped('total_employer_tax'))
            wizard.employee_count = len(wizard.entry_ids)
            wizard.selected_count = len(wizard.entry_ids.filtered(lambda e: e.regular_hours > 0))

    @api.depends('entry_ids', 'entry_ids.gross_pay', 'entry_ids.total_employer_tax')
    def _compute_preview_totals(self):
        for wizard in self:
            gross = sum(wizard.entry_ids.mapped('gross_pay'))
            employer_tax = sum(wizard.entry_ids.mapped('total_employer_tax'))
            wizard.total_payroll_cost = gross + employer_tax
            
            # Calculate change from last payroll
            last_payroll = self.env['hr.payslip.run'].search([
                ('company_id', '=', wizard.company_id.id),
                ('state', 'in', ['close', 'paid']),
            ], order='date_end desc', limit=1)
            
            if last_payroll and last_payroll.slip_ids:
                last_total = sum(last_payroll.slip_ids.mapped('net_wage'))
                if last_total > 0:
                    wizard.change_from_last = ((wizard.total_net_pay - last_total) / last_total) * 100
                else:
                    wizard.change_from_last = 0
            else:
                wizard.change_from_last = 0

    @api.depends('payslip_run_id')
    def _compute_payslip_count(self):
        for wizard in self:
            if wizard.payslip_run_id:
                wizard.payslip_count = len(wizard.payslip_run_id.slip_ids)
            else:
                wizard.payslip_count = 0

    @api.onchange('pay_period_id')
    def _onchange_pay_period_id(self):
        """Update dates when period is selected."""
        if self.pay_period_id:
            self.date_start = self.pay_period_id.date_start
            self.date_end = self.pay_period_id.date_end
            if self.pay_period_id.pay_date:
                self.pay_date = self.pay_period_id.pay_date

    @api.onchange('pay_schedule', 'date_start')
    def _onchange_pay_schedule(self):
        """Adjust date_end based on pay schedule"""
        if self.date_start and self.pay_schedule:
            if self.pay_schedule == 'weekly':
                self.date_end = self.date_start + relativedelta(days=6)
            elif self.pay_schedule == 'biweekly':
                self.date_end = self.date_start + relativedelta(days=13)
            elif self.pay_schedule == 'semi_monthly':
                if self.date_start.day <= 15:
                    self.date_end = self.date_start.replace(day=15)
                else:
                    self.date_end = self.date_start + relativedelta(months=1, day=1) - relativedelta(days=1)
            elif self.pay_schedule == 'monthly':
                self.date_end = self.date_start + relativedelta(months=1, day=1) - relativedelta(days=1)

    @api.onchange('company_id', 'pay_schedule')
    def _onchange_load_employees(self):
        """Load employees when company or schedule changes."""
        self._load_employees()

    def _load_employees(self):
        """Load all active employees into entries."""
        if not self.company_id:
                return
            
        # Clear existing entries
        self.entry_ids = [(5, 0, 0)]
        
        # Find active employees in the company
        employees = self.env['hr.employee'].search([
                ('company_id', '=', self.company_id.id),
            ('active', '=', True),
        ])
        
        entries = []
        for employee in employees:
            # Get payment method from Fusion Payroll settings
            payment_method = getattr(employee, 'payment_method', 'cheque') or 'cheque'
            
            # Get vacation pay percent from Fusion Payroll settings (vacation_rate field)
            vacation_percent = getattr(employee, 'vacation_rate', 4.0) or 4.0
            
            entry_vals = {
                'employee_id': employee.id,
                'payment_method': payment_method,
                'vacation_pay_percent': vacation_percent,
                'regular_hours': 0,
                'stat_holiday_hours': 0,
            }
            entries.append((0, 0, entry_vals))
        
        self.entry_ids = entries

    def action_add_employee(self):
        """Open dialog to add an employee."""
        return {
            'type': 'ir.actions.act_window',
            'name': _('Add Employee'),
            'res_model': 'hr.employee',
            'view_mode': 'kanban,list,form',
            'target': 'new',
            'context': {
                'default_company_id': self.company_id.id,
                'payroll_wizard_id': self.id,
            },
        }

    def action_load_attendance(self):
        """Load attendance hours for all employees in the period."""
        for entry in self.entry_ids:
            entry.action_load_attendance_hours()
        
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': _('Attendance Loaded'),
                'message': _('Loaded attendance hours for %d employees.') % len(self.entry_ids),
                'type': 'success',
            },
        }

    def action_preview_payroll(self):
        """Show the preview page with totals."""
        self.ensure_one()
        
        # Validate that at least one employee has hours
        entries_with_pay = self.entry_ids.filtered(
            lambda e: e.regular_hours > 0 or e.stat_holiday_hours > 0 or e.stat_pay_avg_daily_wage > 0
        )
        
        if not entries_with_pay:
            raise UserError(_("No employees have hours entered. Please enter hours for at least one employee."))
        
        # Set state to preview (this was incorrectly indented before)
        self.state = 'preview'
            
        return {
            'type': 'ir.actions.act_window',
            'name': _('Run Payroll'),
            'res_model': 'run.payroll.wizard',
            'res_id': self.id,
            'view_mode': 'form',
            'target': 'current',
            'context': {'form_view_ref': 'fusion_payroll.run_payroll_wizard_view_form'},
        }

    def action_back_to_entry(self):
        """Go back to the entry page."""
        self.ensure_one()
        self.state = 'entry'

        return {
            'type': 'ir.actions.act_window',
            'name': _('Run Payroll'),
            'res_model': 'run.payroll.wizard',
            'res_id': self.id,
            'view_mode': 'form',
            'target': 'current',
            'context': {'form_view_ref': 'fusion_payroll.run_payroll_wizard_view_form'},
        }

    def action_save_for_later(self):
        """Save the payroll entries for later without processing."""
        self.ensure_one()
        
        # Update pay period status to in_progress if using periods
        if self.pay_period_id:
            self.pay_period_id.write({'state': 'in_progress'})
        
        return {
            'type': 'ir.actions.client',
            'tag': 'display_notification',
            'params': {
                'title': _('Payroll Saved'),
                'message': _('Payroll entries have been saved. You can continue later.'),
                'type': 'success',
                'next': {'type': 'ir.actions.act_window_close'},
            },
        }

    def action_submit_payroll(self):
        """Submit the payroll - create payslips and journal entries."""
        self.ensure_one()
        return self.action_generate_payslips()

    def action_generate_payslips(self):
        """Generate payslips for all entries with hours."""
        self.ensure_one()
        
        # Get entries with hours
        entries_with_pay = self.entry_ids.filtered(
            lambda e: e.regular_hours > 0 or e.stat_holiday_hours > 0 or e.stat_pay_avg_daily_wage > 0
        )
        
        if not entries_with_pay:
            raise UserError(_("No employees have hours entered. Please enter hours for at least one employee."))
        
        # Create payslip batch
        batch_name = f"Payroll {self.date_start.strftime('%Y-%m-%d')} to {self.date_end.strftime('%Y-%m-%d')}"
        payslip_run = self.env['hr.payslip.run'].create({
            'name': batch_name,
            'date_start': self.date_start,
            'date_end': self.date_end,
            'company_id': self.company_id.id,
        })
        
        # Generate payslips for each entry
        for entry in entries_with_pay:
            # Generate payslip name
            payslip_name = f"Payslip - {entry.employee_id.name} - {self.date_start.strftime('%Y/%m')}"
            
            # Create payslip
            payslip_vals = {
                'name': payslip_name,
                'employee_id': entry.employee_id.id,
                'date_from': self.date_start,
                'date_to': self.date_end,
                'payslip_run_id': payslip_run.id,
                'company_id': self.company_id.id,
            }
            
            # Add contract_id if employee has one
            if hasattr(entry.employee_id, 'contract_id') and entry.employee_id.contract_id:
                payslip_vals['contract_id'] = entry.employee_id.contract_id.id
            
            # Create the payslip (this was incorrectly indented before)
            payslip = self.env['hr.payslip'].create(payslip_vals)
                
            # Add inputs from Fusion Payroll entry
            self._add_fusion_payroll_inputs(payslip, entry)
            
            # Compute sheet
            payslip.compute_sheet()
            
            # Override computed values with Fusion Payroll calculations
            self._apply_fusion_payroll_values(payslip, entry)
        
        self.payslip_run_id = payslip_run
        
        # Update pay period status if using periods
        if self.pay_period_id:
            self.pay_period_id.write({
                'state': 'in_progress',
                'payslip_run_id': payslip_run.id,
            })
        
        # Create cheques for employees with payment method = 'cheque'
        cheques_created = self._create_cheques_for_batch(payslip_run)
        
        # If cheques were created, show print option
        if cheques_created:
            return self._action_payroll_complete_with_cheques(payslip_run, cheques_created)
        
        return self.action_view_payslips()
    
    def _add_fusion_payroll_inputs(self, payslip, entry):
        """Add salary inputs from Fusion Payroll entry to payslip."""
        # Find or create input types
        InputType = self.env['hr.payslip.input.type']
        Input = self.env['hr.payslip.input']
        
        # Regular Hours input
        if entry.regular_hours > 0:
            hours_type = InputType.search([('code', '=', 'HOURS')], limit=1)
            if not hours_type:
                hours_type = InputType.search([('code', '=', 'WORKED_HOURS')], limit=1)
            if not hours_type:
                hours_type = InputType.create({
                    'name': 'Worked Hours',
                    'code': 'HOURS',
                })
            Input.create({
                'payslip_id': payslip.id,
                'input_type_id': hours_type.id,
                'amount': entry.regular_hours,
            })
        
        # Regular Pay (calculated amount)
        if entry.regular_pay > 0:
            reg_pay_type = InputType.search([('code', '=', 'REGPAY')], limit=1)
            if not reg_pay_type:
                reg_pay_type = InputType.create({
                    'name': 'Regular Pay',
                    'code': 'REGPAY',
                })
            Input.create({
                'payslip_id': payslip.id,
                'input_type_id': reg_pay_type.id,
                'amount': entry.regular_pay,
            })
        
        # Vacation Pay
        if entry.vacation_pay > 0:
            vac_type = InputType.search([('code', '=', 'VAC')], limit=1)
            if not vac_type:
                vac_type = InputType.create({
                    'name': 'Vacation Pay',
                    'code': 'VAC',
                })
            Input.create({
                'payslip_id': payslip.id,
                'input_type_id': vac_type.id,
                'amount': entry.vacation_pay,
            })
        
        # Stat Holiday Pay
        if entry.stat_holiday_pay > 0:
            stat_type = InputType.search([('code', '=', 'STAT')], limit=1)
            if not stat_type:
                stat_type = InputType.create({
                    'name': 'Stat Holiday Pay',
                    'code': 'STAT',
                })
            Input.create({
                'payslip_id': payslip.id,
                'input_type_id': stat_type.id,
                'amount': entry.stat_holiday_pay,
            })
        
        # Stat Pay (Average Daily Wage)
        if entry.stat_pay_avg_daily_wage > 0:
            stat_avg_type = InputType.search([('code', '=', 'STATAVG')], limit=1)
            if not stat_avg_type:
                stat_avg_type = InputType.create({
                    'name': 'Stat Pay - Avg Daily Wage',
                    'code': 'STATAVG',
                })
            Input.create({
                'payslip_id': payslip.id,
                'input_type_id': stat_avg_type.id,
                'amount': entry.stat_pay_avg_daily_wage,
            })
    
    def _apply_fusion_payroll_values(self, payslip, entry):
        """Apply Fusion Payroll calculated values to payslip lines."""
        # Get or create salary rule categories
        Category = self.env['hr.salary.rule.category']
        
        # Find categories
        gross_cat = Category.search([('code', '=', 'GROSS')], limit=1)
        ded_cat = Category.search([('code', '=', 'DED')], limit=1)
        net_cat = Category.search([('code', '=', 'NET')], limit=1)
        
        # Update or create payslip lines with Fusion Payroll values
        # This directly sets the computed amounts
        
        # Update basic wage on payslip
        payslip.write({
            'basic_wage': entry.gross_pay,
            'net_wage': entry.net_pay,
        })
        
        # Update payslip lines
        for line in payslip.line_ids:
            if line.code == 'BASIC' or line.code == 'GROSS':
                line.write({'amount': entry.gross_pay, 'total': entry.gross_pay})
            elif line.code == 'NET':
                line.write({'amount': entry.net_pay, 'total': entry.net_pay})
        
        # Create additional lines if they don't exist
        self._ensure_payslip_lines(payslip, entry)
    
    def _ensure_payslip_lines(self, payslip, entry):
        """Ensure all Fusion Payroll calculated values have corresponding payslip lines."""
        Line = self.env['hr.payslip.line']
        Rule = self.env['hr.salary.rule']
        Category = self.env['hr.salary.rule.category']
        
        # Get categories
        gross_cat = Category.search([('code', '=', 'GROSS')], limit=1)
        ded_cat = Category.search([('code', '=', 'DED')], limit=1)
        alw_cat = Category.search([('code', '=', 'ALW')], limit=1)
        
        # Helper to find or create rule
        def get_or_create_rule(code, name, category, sequence=100):
            rule = Rule.search([('code', '=', code)], limit=1)
            if not rule and category:
                struct = payslip.struct_id or self.env['hr.payroll.structure'].search([], limit=1)
                rule = Rule.create({
                    'name': name,
                    'code': code,
                    'category_id': category.id,
                    'sequence': sequence,
                    'struct_id': struct.id if struct else False,
                    'amount_select': 'fix',
                    'amount_fix': 0,
                })
            return rule
        
        # Check and add lines
        existing_codes = payslip.line_ids.mapped('code')
        
        # Regular Pay line
        if 'REGPAY' not in existing_codes and entry.regular_pay > 0:
            rule = get_or_create_rule('REGPAY', 'Regular Pay', gross_cat, 10)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Regular Pay',
                    'code': 'REGPAY',
                    'category_id': gross_cat.id if gross_cat else False,
                    'sequence': 10,
                    'quantity': entry.regular_hours,
                    'rate': entry.hourly_rate,
                    'amount': entry.regular_pay,
                    'total': entry.regular_pay,
                })
        
        # Vacation Pay line
        if 'VAC' not in existing_codes and entry.vacation_pay > 0:
            rule = get_or_create_rule('VAC', 'Vacation Pay', alw_cat or gross_cat, 20)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Vacation Pay',
                    'code': 'VAC',
                    'category_id': (alw_cat or gross_cat).id if (alw_cat or gross_cat) else False,
                    'sequence': 20,
                    'quantity': 1,
                    'rate': entry.vacation_pay_percent,
                    'amount': entry.vacation_pay,
                    'total': entry.vacation_pay,
                })
        
        # Stat Holiday Pay line
        if 'STAT' not in existing_codes and entry.stat_holiday_pay > 0:
            rule = get_or_create_rule('STAT', 'Stat Holiday Pay', alw_cat or gross_cat, 25)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Stat Holiday Pay',
                    'code': 'STAT',
                    'category_id': (alw_cat or gross_cat).id if (alw_cat or gross_cat) else False,
                    'sequence': 25,
                    'quantity': entry.stat_holiday_hours,
                    'rate': entry.hourly_rate,
                    'amount': entry.stat_holiday_pay,
                    'total': entry.stat_holiday_pay,
                })
        
        # Employee Tax lines (negative deductions)
        if 'FIT' not in existing_codes and 'INCOMETAX' not in existing_codes and entry.income_tax > 0:
            rule = get_or_create_rule('FIT', 'Federal Income Tax', ded_cat, 100)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Income Tax',
                    'code': 'FIT',
                    'category_id': ded_cat.id if ded_cat else False,
                    'sequence': 100,
                    'quantity': 1,
                    'rate': 100,
                    'amount': -entry.income_tax,
                    'total': -entry.income_tax,
                })
        
        if 'EI' not in existing_codes and 'EI_EMP' not in existing_codes and entry.employment_insurance > 0:
            rule = get_or_create_rule('EI_EMP', 'Employment Insurance', ded_cat, 110)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Employment Insurance',
                    'code': 'EI_EMP',
                    'category_id': ded_cat.id if ded_cat else False,
                    'sequence': 110,
                    'quantity': 1,
                    'rate': 100,
                    'amount': -entry.employment_insurance,
                    'total': -entry.employment_insurance,
                })
        
        if 'CPP' not in existing_codes and 'CPP_EMP' not in existing_codes and entry.cpp > 0:
            rule = get_or_create_rule('CPP_EMP', 'Canada Pension Plan', ded_cat, 120)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Canada Pension Plan',
                    'code': 'CPP_EMP',
                    'category_id': ded_cat.id if ded_cat else False,
                    'sequence': 120,
                    'quantity': 1,
                    'rate': 100,
                    'amount': -entry.cpp,
                    'total': -entry.cpp,
                })
        
        if 'CPP2' not in existing_codes and 'CPP2_EMP' not in existing_codes and entry.cpp2 > 0:
            rule = get_or_create_rule('CPP2_EMP', 'Second CPP', ded_cat, 125)
            if rule:
                Line.create({
                    'slip_id': payslip.id,
                    'salary_rule_id': rule.id,
                    'name': 'Second Canada Pension Plan',
                    'code': 'CPP2_EMP',
                    'category_id': ded_cat.id if ded_cat else False,
                    'sequence': 125,
                    'quantity': 1,
                    'rate': 100,
                    'amount': -entry.cpp2,
                    'total': -entry.cpp2,
                })
    
    def _create_cheques_for_batch(self, payslip_run):
        """Create cheque records for employees paid by cheque."""
        cheques = self.env['payroll.cheque']
        
        for payslip in payslip_run.slip_ids:
            # Check if employee's payment method is cheque
            if hasattr(payslip.employee_id, 'payment_method') and \
               payslip.employee_id.payment_method == 'cheque':
                cheque = self.env['payroll.cheque'].create_from_payslip(payslip)
                if cheque:
                    cheques |= cheque
        
        return cheques
    
    def _action_payroll_complete_with_cheques(self, payslip_run, cheques):
        """Show completion wizard with option to print cheques."""
        return {
            'type': 'ir.actions.act_window',
            'name': _('Payroll Complete'),
            'res_model': 'payroll.cheque.print.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'default_payslip_run_id': payslip_run.id,
                'default_cheque_ids': [(6, 0, cheques.ids)],
                'default_cheque_count': len(cheques),
            },
        }
    
    def action_print_cheques(self):
        """Print all cheques for the current batch."""
        self.ensure_one()
        
        if not self.payslip_run_id:
            raise UserError(_("No payslips have been generated yet."))
        
        cheques = self.env['payroll.cheque'].search([
            ('payslip_run_id', '=', self.payslip_run_id.id),
        ])
        
        if not cheques:
            raise UserError(_("No cheques found for this payroll batch."))
        
        # Assign numbers and mark as printed
        for cheque in cheques:
            cheque.action_assign_number()
        
        return self.env.ref('fusion_payroll.action_report_payroll_cheque').report_action(cheques)

    def action_view_payslips(self):
        """View generated payslips."""
        self.ensure_one()
        
        if not self.payslip_run_id:
            raise UserError(_("No payslips have been generated yet."))
        
        return {
            'type': 'ir.actions.act_window',
            'name': _('Payslip Batch'),
            'res_model': 'hr.payslip.run',
            'res_id': self.payslip_run_id.id,
            'view_mode': 'form',
            'target': 'current',
        }

    def action_confirm_payslips(self):
        """Confirm all generated payslips."""
        self.ensure_one()
        
        if not self.payslip_run_id:
            raise UserError(_("No payslips have been generated yet."))
        
        # Confirm all payslips in the batch
        for payslip in self.payslip_run_id.slip_ids:
            if payslip.state == 'draft':
                payslip.action_payslip_done()
        
        # Update pay period status
        if self.pay_period_id:
            self.pay_period_id.write({'state': 'paid'})
        
        return self.action_view_payslips()

    @api.model
    def action_open_run_payroll(self):
        """Open the Run Payroll wizard with pre-loaded data."""
        # Check/create pay period settings
        settings = self.env['payroll.pay.period.settings'].get_or_create_settings()
        
        # Auto-generate periods for past 6 months and future 6 months
        self.env['payroll.pay.period'].auto_generate_periods_if_needed(
            company_id=self.env.company.id,
            schedule_type=settings.schedule_type,
        )
        
        # Find the current pay period (today falls within it)
        today = fields.Date.context_today(self)
        current_period = self.env['payroll.pay.period'].search([
            ('company_id', '=', self.env.company.id),
            ('schedule_type', '=', settings.schedule_type),
            ('date_start', '<=', today),
            ('date_end', '>=', today),
        ], limit=1)
        
        # If no current period, find the next upcoming one
        if not current_period:
            current_period = self.env['payroll.pay.period'].search([
                ('company_id', '=', self.env.company.id),
                ('schedule_type', '=', settings.schedule_type),
                ('date_start', '>', today),
            ], order='date_start asc', limit=1)
        
        # Create wizard with default period
        wizard_vals = {
            'company_id': self.env.company.id,
            'pay_schedule': settings.schedule_type,
        }
        if current_period:
            wizard_vals['pay_period_id'] = current_period.id
            wizard_vals['date_start'] = current_period.date_start
            wizard_vals['date_end'] = current_period.date_end
            wizard_vals['pay_date'] = current_period.pay_date
        
        wizard = self.create(wizard_vals)
        wizard._load_employees()
        
        schedule_labels = {
            'weekly': 'Weekly',
            'biweekly': 'Bi-Weekly',
            'semi_monthly': 'Semi-Monthly',
            'monthly': 'Monthly',
        }
        schedule = schedule_labels.get(settings.schedule_type, 'Bi-Weekly')
        
        return {
            'type': 'ir.actions.act_window',
            'name': _('Run Payroll: %s') % schedule,
            'res_model': 'run.payroll.wizard',
            'res_id': wizard.id,
            'view_mode': 'form',
            'target': 'current',
            'context': {'form_view_ref': 'fusion_payroll.run_payroll_wizard_view_form'},
        }
