from odoo import models, api
from collections import defaultdict
from datetime import datetime, timedelta, date

# Constants
PRODUCTION_LEAD_DAYS = {
    'BHMS 1.2V': 60,
    'BHMS 2V': 30,
    'BHMS 12V': 30,
    'BHMS 48V': 30,
    'BMS-LV 100A': 30,
    'BMS-LV 40A': 30,
    'MC 250W': 45,
    'HeartTarang': 30,
}

MONTH_NAMES = [
    'April', 'May', 'June', 'July', 'August', 'September',
    'October', 'November', 'December', 'January', 'February', 'March'
]

class ReportBillingTarget(models.AbstractModel):
    _name = 'report.sos_sales.report_billing_target'
    _description = 'Billing Target Report'

    def get_month_start_dates(self, fy_start_year):
        dates = {}
        for i, name in enumerate(MONTH_NAMES):
            month = i + 4 if i < 9 else i - 8
            year = fy_start_year if i < 9 else fy_start_year + 1
            dates[name] = datetime(year, month, 1)
        return dates

    @api.model
    def _get_report_values(self, docids, data=None):
        fy_start_year = 2024  # Change to dynamic year if needed
        month_start_dates = self.get_month_start_dates(fy_start_year)

        today = date.today()
        fy_year = today.year if today.month >= 4 else today.year - 1
        current_fy = f"FY {fy_year}-{fy_year + 1}"

        result = defaultdict(lambda: defaultdict(lambda: defaultdict(float)))
        records = self.env['sos_sales_plan_target'].search([
                ('financial_year', '=', current_fy)
            ])

        for rec in records:
            exec_name = rec.sales_executive.name
            for line in rec.line_ids:
                product = line.product
                if not product:
                    continue
                lead_days = PRODUCTION_LEAD_DAYS.get(product, 0)

                for month in MONTH_NAMES:
                    short = month.lower()[:3]
                    value = getattr(line, f"{short}_value", 0.0)
                    if value:
                        source_start = month_start_dates[month]
                        next_month = source_start.replace(day=28) + timedelta(days=4)
                        last_day_of_month = next_month.replace(day=1) - timedelta(days=1)

                        billed_date = last_day_of_month + timedelta(days=lead_days)


                        # Match billed_date to one of the financial year months
                        for name, start_date in month_start_dates.items():
                            if start_date.month == billed_date.month and start_date.year == billed_date.year:
                                billed_month = name
                                break
                        else:
                            billed_month = None

                        if billed_month in MONTH_NAMES:
                            result[exec_name][billed_month][product] += value


        # Step 2: Filter products and compute totals
        filtered_products_by_exec = defaultdict(set)
        display_totals = defaultdict(lambda: defaultdict(float))

        for exec_name, month_data in result.items():
            for month, prod_data in month_data.items():
                for product, val in prod_data.items():
                    if val > 0:
                        filtered_products_by_exec[exec_name].add(product)
                        display_totals[exec_name][month] += val
        overall_monthly_totals = defaultdict(float)

        for exec_name, month_totals in display_totals.items():
            for month, value in month_totals.items():
                overall_monthly_totals[month] += value
        grand_total = sum(overall_monthly_totals.values())
        return {
            'doc_ids': docids,
            'doc_model': 'sos_sales_plan_target',
            'billing_data': result,
            'month_names': MONTH_NAMES,
            'filtered_products_by_exec': filtered_products_by_exec,
            'monthly_totals': display_totals,
            'overall_monthly_totals': overall_monthly_totals,
            'grand_total': grand_total, 
        }
