
from odoo import models, fields, api
from datetime import date
import re
import calendar


class SOS_Sales_Achievement_Report(models.Model):
    _name = 'sos_sales_achievement_report'
    _description = 'Sosaley Sales Achievement Report'
    _rec_name='financial_year'
    _sql_constraints = [
        ('unique_financial_year_sales_person', 'UNIQUE(financial_year, sales_person)', 'The combination of Financial Year and Sales Person must be unique.')
    ]

    financial_year = fields.Char(string="Financial Year", default=lambda self: self._get_financial_year())
    sales_person = fields.Many2one('res.users', string='Sales person',required=True)
    overall_target = fields.Float(string="Overall Target")
    opening_balance = fields.Float(string="Opening Balance")
    planned_target_april = fields.Float(string="Planned For April")
    actual_target_april = fields.Float(string="Actual For April")
    billed_target_april = fields.Float(string="Billed For April")
    yet_to_billed_target_april = fields.Float(string="Yet to Billed For April")
    collected_target_april = fields.Float(string="Collected For April")
    achievement_percentage_april = fields.Char(string="Achievement Percentage For April", compute="_compute_achievement_percentage", store=True)
    planned_target_may = fields.Float(string="Planned For May")
    actual_target_may = fields.Float(string="Actual For May")
    billed_target_may = fields.Float(string="Billed For May")
    yet_to_billed_target_may = fields.Float(string="Yet to Billed For May")
    collected_target_may = fields.Float(string="Collected For May")
    achievement_percentage_may = fields.Char(string="Achievement Percentage For May", compute="_compute_achievement_percentage", store=True)
    planned_target_june = fields.Float(string="Planned For June")
    actual_target_june = fields.Float(string="Actual For June")
    billed_target_june = fields.Float(string="Billed For June")
    yet_to_billed_target_june = fields.Float(string="Yet to Billed For June")
    collected_target_june = fields.Float(string="Collected For June")
    achievement_percentage_june = fields.Char(string="Achievement Percentage For June", compute="_compute_achievement_percentage", store=True)
    planned_target_july = fields.Float(string="Planned For July")
    actual_target_july = fields.Float(string="Actual For July")
    billed_target_july = fields.Float(string="Billed For July")
    yet_to_billed_target_july = fields.Float(string="Yet to Billed For July")
    collected_target_july = fields.Float(string="Collected For July")
    achievement_percentage_july = fields.Char(string="Achievement Percentage For July", compute="_compute_achievement_percentage", store=True)
    planned_target_august = fields.Float(string="Planned For August")
    actual_target_august = fields.Float(string="Actual For August")
    billed_target_august = fields.Float(string="Billed For August")
    yet_to_billed_target_august = fields.Float(string="Yet to Billed For August")
    collected_target_august = fields.Float(string="Collected For August")
    achievement_percentage_august = fields.Char(string="Achievement Percentage For August", compute="_compute_achievement_percentage", store=True)
    planned_target_september = fields.Float(string="Planned For September")
    actual_target_september = fields.Float(string="Actual For September")
    billed_target_september = fields.Float(string="Billed For September")
    yet_to_billed_target_september = fields.Float(string="Yet to Billed For September")
    collected_target_september = fields.Float(string="Collected For September")
    achievement_percentage_september = fields.Char(string="Achievement Percentage For September", compute="_compute_achievement_percentage", store=True)
    planned_target_october = fields.Float(string="Planned For October")
    actual_target_october = fields.Float(string="Actual For October")
    billed_target_october = fields.Float(string="Billed For October")
    yet_to_billed_target_october = fields.Float(string="Yet to Billed For October")
    collected_target_october = fields.Float(string="Collected For October")
    achievement_percentage_october = fields.Char(string="Achievement Percentage For October", compute="_compute_achievement_percentage", store=True)
    planned_target_november = fields.Float(string="Planned For November")
    actual_target_november = fields.Float(string="Actual For November")
    billed_target_november = fields.Float(string="Billed For November")
    yet_to_billed_target_november = fields.Float(string="Yet to Billed For November")
    collected_target_november = fields.Float(string="Collected For November")
    achievement_percentage_november = fields.Char(string="Achievement Percentage For November", compute="_compute_achievement_percentage", store=True)
    planned_target_december = fields.Float(string="Planned For December")
    actual_target_december = fields.Float(string="Actual For December")
    billed_target_december = fields.Float(string="Billed For December")
    yet_to_billed_target_december = fields.Float(string="Yet to Billed For December")
    collected_target_december = fields.Float(string="Collected For December")
    achievement_percentage_december = fields.Char(string="Achievement Percentage For December", compute="_compute_achievement_percentage", store=True)
    planned_target_january = fields.Float(string="Planned For January")
    actual_target_january = fields.Float(string="Actual For January")
    billed_target_january = fields.Float(string="Billed For January")
    yet_to_billed_target_january = fields.Float(string="Yet to Billed For January")
    collected_target_january = fields.Float(string="Collected For January")
    achievement_percentage_january = fields.Char(string="Achievement Percentage For January", compute="_compute_achievement_percentage", store=True)
    planned_target_february = fields.Float(string="Planned For February")
    actual_target_february = fields.Float(string="Actual For February")
    billed_target_february = fields.Float(string="Billed For February")
    yet_to_billed_target_february = fields.Float(string="Yet to Billed For February")
    collected_target_february = fields.Float(string="Collected For February")
    achievement_percentage_february = fields.Char(string="Achievement Percentage For February", compute="_compute_achievement_percentage", store=True)
    planned_target_march = fields.Float(string="Planned For March")
    actual_target_march = fields.Float(string="Actual For March")
    billed_target_march = fields.Float(string="Billed For March")
    yet_to_billed_target_march = fields.Float(string="Yet to Billed For March")

    collected_target_march = fields.Float(string="Collected For March")
    achievement_percentage_march = fields.Char(string="Achievement Percentage For March", compute="_compute_achievement_percentage", store=True)
    planned_target_total = fields.Float(string="Planned Total", compute="_compute_planned_total_target", store=True)
    actual_target_total = fields.Float(string="Actual Total", compute="_compute_actual_total_target", store=True)
    achievement_percentage_total = fields.Char(string="Achievement Percentage For Total", compute="_compute_achievement_percentage_total", store=True)
    billed_target_total = fields.Char(string="Billed For Total", compute="_compute_billed_total_target", store=True)
    yet_to_billed_target_total  = fields.Char(string="Billed For Total", compute="_compute_yet_to_billed_total_target", store=True)
    collected_target_total = fields.Char(string="collected For Total", compute="_compute_collected_total_target", store=True)
    can_edit_billed_target = fields.Boolean(
        string="Can Edit Billed Target",
        compute="_compute_can_edit_billed_target",
        store=False,
    )
    ytd_target = fields.Float(string="YTD Total", store=True, compute="_compute_ytd_target")
    ytd_sales = fields.Float(string="YTD Sales", store=True, compute="_compute_ytd_sales_target")
    ytd_sales_percentage = fields.Float(string="YTD Sales Percentage", store=True, compute="_compute_ytd_sales_percentage")
    ytd_yet_to_billed = fields.Float(string="YTD Billed", store=True,compute="_compute_ytd_yet_to_billed")
    ytd_billed = fields.Float(string="YTD Billed", store=True,compute="_compute_ytd_billed")
    ytd_collected = fields.Float(string="YTD Collected", store=True,compute="_compute_ytd_collected")
    line_ids = fields.One2many('sos_sales_achievement_report_brief', 'ref_id',copy=True)
    
    @api.depends(
            'yet_to_billed_target_april', 'yet_to_billed_target_may', 'yet_to_billed_target_june',
            'yet_to_billed_target_july', 'yet_to_billed_target_august', 'yet_to_billed_target_september',
            'yet_to_billed_target_october', 'yet_to_billed_target_november', 'yet_to_billed_target_december',
            'yet_to_billed_target_january', 'yet_to_billed_target_february', 'yet_to_billed_target_march'
        )
    def _compute_ytd_yet_to_billed(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]
        current_month = date.today().month

        # In FY April to March, January=10th index
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            for m in months_to_include:
                total += getattr(rec, f'yet_to_billed_target_{m}', 0.0)
            rec.ytd_yet_to_billed = total
    def action_view_billed_lines(self):
        self.ensure_one()

        # Extract the month from context
        month = int(self.env.context.get('month', 0))
        if not month:
            month = 4  # fallback to April

        # You must extract year (hardcoded or dynamic based on financial year logic)
        # Assuming your main model has `financial_year = 'FY 2025-2026'`
        match = re.search(r'FY\s*(\d{4})', self.financial_year or '')
        if match:
            year = int(match.group(1))
        else:
            year = date.today().year  # fallback

        # Get month boundaries
        last_day = calendar.monthrange(year, month)[1]
        from_date = f'{year}-{month:02d}-01'
        to_date = f'{year}-{month:02d}-{last_day:02d}'
        # Fetch Billed lines
        billed_lines = self.env['sos_billing_collection'].search([
            ('sales_person', '=', self.sales_person.id),
            ('action_status', '=', self.env.context.get('action')),
            ('date_of_action', '>=', from_date),
            ('date_of_action', '<=', to_date),
        ])
        return {
            'name': f"{self.env.context.get('action')} Items",
            'type': 'ir.actions.act_window',
            'res_model': 'sos_billed_collection_wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'default_billed_line_ids': [(6, 0, billed_lines.ids)],
                'default_parent_id': self.id,
            }
        }
    def action_view_brief_lines(self):
        self.ensure_one()
        domain = [('ref_id', '=', self.id)]

        # Extract year from 'FY 2025-2026'
        match = re.search(r'FY\s*(\d{4})', self.financial_year or '')
        if match:
            year = int(match.group(1))
        else:
            raise ValueError(f"Unable to extract year from financial year: {self.financial_year}")

        # Filter by month if present
        month = int(self.env.context.get('month', 0))
        if month:
            domain.append(('action_date', '>=', f'{year}-{month:02d}-01'))
            last_day = calendar.monthrange(year, month)[1]
            domain.append(('action_date', '<=', f'{year}-{month:02d}-{last_day:02d}'))

        brief_lines = self.env['sos_sales_achievement_report_brief'].search(domain)

        return {
            'name': 'Achievement Brief Lines',
            'type': 'ir.actions.act_window',
            'res_model': 'sos_sales_achievement_report_brief_wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {
                'default_brief_line_ids': [(6, 0, brief_lines.ids)],
                'default_parent_id': self.id,
            }
        }

    @api.depends(
        'collected_target_april', 'collected_target_may', 'collected_target_june',
        'collected_target_july', 'collected_target_august', 'collected_target_september',
        'collected_target_october', 'collected_target_november', 'collected_target_december',
        'collected_target_january', 'collected_target_february', 'collected_target_march'
    )
    def _compute_ytd_collected(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]
        current_month = date.today().month

        # In FY April to March, January=10th index
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            for m in months_to_include:
                total += getattr(rec, f'collected_target_{m}', 0.0)
            rec.ytd_collected = total
    @api.depends(
        'billed_target_april', 'billed_target_may', 'billed_target_june',
        'billed_target_july', 'billed_target_august', 'billed_target_september',
        'billed_target_october', 'billed_target_november', 'billed_target_december',
        'billed_target_january', 'billed_target_february', 'billed_target_march'
    )
    def _compute_ytd_billed(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]
        current_month = date.today().month

        # In FY April to March, January=10th index
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            for m in months_to_include:
                total += getattr(rec, f'billed_target_{m}', 0.0)
            rec.ytd_billed = total
    @api.depends(
        'achievement_percentage_april', 'achievement_percentage_may', 'achievement_percentage_june',
        'achievement_percentage_july', 'achievement_percentage_august', 'achievement_percentage_september',
        'achievement_percentage_october', 'achievement_percentage_november', 'achievement_percentage_december',
        'achievement_percentage_january', 'achievement_percentage_february', 'achievement_percentage_march',
    )
    def _compute_ytd_sales_percentage(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]

        current_month = date.today().month
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            count = 0
            for m in months_to_include:
                raw = getattr(rec, f'achievement_percentage_{m}', '0').replace('%', '').strip()
                try:
                    val = float(raw)
                    total += val
                    count += 1
                except (ValueError, TypeError):
                    continue
            rec.ytd_sales_percentage = round(total / count, 2) if count else 0.0
    @api.depends(
        'actual_target_april', 'actual_target_may', 'actual_target_june',
        'actual_target_july', 'actual_target_august', 'actual_target_september',
        'actual_target_october', 'actual_target_november', 'actual_target_december',
        'actual_target_january', 'actual_target_february', 'actual_target_march'
    )
    def _compute_ytd_sales_target(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]
        current_month = date.today().month

        # In FY April to March, January=10th index
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            for m in months_to_include:
                total += getattr(rec, f'actual_target_{m}', 0.0)
            rec.ytd_sales = total
    @api.depends(
        'planned_target_april', 'planned_target_may', 'planned_target_june',
        'planned_target_july', 'planned_target_august', 'planned_target_september',
        'planned_target_october', 'planned_target_november', 'planned_target_december',
        'planned_target_january', 'planned_target_february', 'planned_target_march'
    )
    def _compute_ytd_target(self):
        month_map = [
            'april', 'may', 'june', 'july', 'august', 'september',
            'october', 'november', 'december',
            'january', 'february', 'march'
        ]
        current_month = date.today().month

        # In FY April to March, January=10th index
        if current_month >= 4:
            months_to_include = month_map[:current_month - 4 + 1]
        else:
            months_to_include = month_map[:current_month + 9 + 1]

        for rec in self:
            total = 0.0
            for m in months_to_include:
                total += getattr(rec, f'planned_target_{m}', 0.0)
            rec.ytd_target = total

    @api.depends_context('uid')
    def _compute_can_edit_billed_target(self):
        for record in self:
            record.can_edit_billed_target = (
                self.env.user.has_group('sos_inventory.sos_finance_user') or
                self.env.user.has_group('sos_inventory.sos_management_user')
            )
    @api.depends(
        'collected_target_april','collected_target_may','collected_target_june',
        'collected_target_july','collected_target_august','collected_target_september',
        'collected_target_october','collected_target_november','collected_target_december',
        'collected_target_january','collected_target_february','collected_target_march'
    )
    def _compute_collected_total_target(self):
        for record in self:
            record.collected_target_total = sum([
                record.collected_target_april or 0,
                record.collected_target_may or 0,
                record.collected_target_june or 0,
                record.collected_target_july or 0,
                record.collected_target_august or 0,
                record.collected_target_september or 0,
                record.collected_target_october or 0,
                record.collected_target_november or 0,
                record.collected_target_december or 0,
                record.collected_target_january or 0,
                record.collected_target_february or 0,
                record.collected_target_march or 0
            ])
    @api.depends(
        'billed_target_april','billed_target_may','billed_target_june',
        'billed_target_july','billed_target_august','billed_target_september',
        'billed_target_october','billed_target_november','billed_target_december',
        'billed_target_january','billed_target_february','billed_target_march'
    )
    def _compute_billed_total_target(self):
        for record in self:
            record.billed_target_total = sum([
                record.billed_target_april or 0,
                record.billed_target_may or 0,
                record.billed_target_june or 0,
                record.billed_target_july or 0,
                record.billed_target_august or 0,
                record.billed_target_september or 0,
                record.billed_target_october or 0,
                record.billed_target_november or 0,
                record.billed_target_december or 0,
                record.billed_target_january or 0,
                record.billed_target_february or 0,
                record.billed_target_march or 0
            ])
    @api.depends('actual_target_total', 'planned_target_total')
    def _compute_achievement_percentage_total(self):
        for record in self:
            if record.planned_target_total != 0:
                record.achievement_percentage_total = f"{round((record.actual_target_total / record.planned_target_total) * 100, 2)}%"
            else:
                record.achievement_percentage_total = "0.00%"

    @api.depends(
        'yet_to_billed_target_april','yet_to_billed_target_may','yet_to_billed_target_june',
        'yet_to_billed_target_july','yet_to_billed_target_august','yet_to_billed_target_september',
        'yet_to_billed_target_october','yet_to_billed_target_november','yet_to_billed_target_december',
        'yet_to_billed_target_january','yet_to_billed_target_february','yet_to_billed_target_march'
    )
    def _compute_yet_to_billed_total_target(self):
        for record in self:
            record.yet_to_billed_target_total = sum([
                record.yet_to_billed_target_april or 0,
                record.yet_to_billed_target_may or 0,
                record.yet_to_billed_target_june or 0,
                record.yet_to_billed_target_july or 0,
                record.yet_to_billed_target_august or 0,
                record.yet_to_billed_target_september or 0,
                record.yet_to_billed_target_october or 0,
                record.yet_to_billed_target_november or 0,
                record.yet_to_billed_target_december or 0,
                record.yet_to_billed_target_january or 0,
                record.yet_to_billed_target_february or 0,
                record.yet_to_billed_target_march or 0
            ])
    @api.depends(
        'planned_target_april','planned_target_may','planned_target_june',
        'planned_target_july','planned_target_august','planned_target_september',
        'planned_target_october','planned_target_november','planned_target_december',
        'planned_target_january','planned_target_february','planned_target_march'
    )
    def _compute_planned_total_target(self):
        for record in self:
            record.planned_target_total = sum([
                record.planned_target_april or 0,
                record.planned_target_may or 0,
                record.planned_target_june or 0,
                record.planned_target_july or 0,
                record.planned_target_august or 0,
                record.planned_target_september or 0,
                record.planned_target_october or 0,
                record.planned_target_november or 0,
                record.planned_target_december or 0,
                record.planned_target_january or 0,
                record.planned_target_february or 0,
                record.planned_target_march or 0
            ])
    @api.depends(
        'actual_target_april','actual_target_may','actual_target_june',
        'actual_target_july','actual_target_august','actual_target_september',
        'actual_target_october','actual_target_november','actual_target_december',
        'actual_target_january','actual_target_february','actual_target_march'
    )
    def _compute_actual_total_target(self):
        for record in self:
            record.actual_target_total = sum([
                record.actual_target_april or 0,
                record.actual_target_may or 0,
                record.actual_target_june or 0,
                record.actual_target_july or 0,
                record.actual_target_august or 0,
                record.actual_target_september or 0,
                record.actual_target_october or 0,
                record.actual_target_november or 0,
                record.actual_target_december or 0,
                record.actual_target_january or 0,
                record.actual_target_february or 0,
                record.actual_target_march or 0
            ])
    @api.depends(
        'actual_target_april','actual_target_may','actual_target_june',
        'actual_target_july','actual_target_august','actual_target_september',
        'actual_target_october','actual_target_november','actual_target_december',
        'actual_target_january','actual_target_february','actual_target_march'
    )
    def _compute_achievement_percentage(self):
        # Loop over all months and calculate achievement percentage dynamically
        for record in self:
            for month in ['april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december', 'january', 'february', 'march']:
                planned_field = f"planned_target_{month}"
                actual_field = f"actual_target_{month}"
                achievement_field = f"achievement_percentage_{month}"
                
                planned_value = getattr(record, planned_field)
                actual_value = getattr(record, actual_field)
                if planned_value != 0:
                    percentage = (actual_value / planned_value) * 100
                    setattr(record, achievement_field, f"{percentage:.2f}%")
                else:
                    setattr(record, achievement_field, "0.00%")
    def _get_financial_year(self):
        current_date = date.today()
        start_year = current_date.year if current_date.month >= 4 else current_date.year - 1
        end_year = start_year + 1
        return f"FY {start_year}-{end_year}"
    def action_report_achievement_btn(self):
        try:
            action = self.env.ref("sos_sales.action_report_achievement").with_context(landscape=True).report_action(self)
            return action
        except ValueError as e:
            print(f"Failed to find report action: {e}")

class SOS_Sales_Achievement_Report_Brief(models.Model):
    _name = 'sos_sales_achievement_report_brief'
    _description = 'Achievement Brief'
    _order = 'action_date desc' 
    ref_id = fields.Many2one('sos_sales_achievement_report', string="Financial Year", ondelete="cascade")
    customer_name = fields.Many2one('sos_customers',string="Customer Name", required=True)
    action_date = fields.Date(string="QP No")
    currency_id = fields.Many2one(
    'res.currency',
    string='Currency',
    default=lambda self: self.env['res.currency'].search([('name', '=', 'INR')], limit=1).id or False
    )
    proposal_value = fields.Monetary(currency_field='currency_id',string="Proposal Value(In Lakhs)")

class SOS_Sales_Achievement_Report_Brief_Wizard(models.TransientModel):
    _name = 'sos_sales_achievement_report_brief_wizard'
    _description = 'Achievement Brief Wizard'
    

    parent_id = fields.Many2one('sos_sales_achievement_report', string="Sales Achievement Report")
    brief_line_ids = fields.Many2many(
        'sos_sales_achievement_report_brief',
        relation='sos_brief_wizard_rel',  # Custom table name
        string="Brief Lines",
        readonly=True
    )
class SosBilledCollectionWizard(models.TransientModel):
    _name = 'sos_billed_collection_wizard'
    _description = 'Billed Collection Lines Wizard'

    parent_id = fields.Many2one('sos_billing_collection')  # adjust accordingly
    billed_line_ids = fields.Many2many(
        'sos_billing_collection',
        string="Billed Lines",
        readonly=True,
    )