# -*- coding: utf-8 -*-
from odoo import models, fields, api


class AccountReport(models.Model):
    _inherit = 'account.report'

    filter_show_full_hierarchy = fields.Boolean(
        string="Show Full Hierarchy Filter",
        default=False,
        help="Enable filter to display accounts in full hierarchical structure"
    )

    def _init_options_show_full_hierarchy(self, options, previous_options):

        if self.filter_show_full_hierarchy:
            if 'filters' not in options:
                options['filters'] = {}
            options['filters']['show_full_hierarchy'] = True
            options['show_full_hierarchy'] = previous_options.get('show_full_hierarchy', False)


    @api.model
    def _get_options_initializers_forced_sequence_map(self):
        res = super()._get_options_initializers_forced_sequence_map()
        res['_init_options_show_full_hierarchy'] = 1035
        return res


class TrialBalanceCustomHandler(models.AbstractModel):
    _name = 'account.trial.balance.report.handler'
    _inherit = 'account.report.custom.handler'
    _description = 'Trial Balance Custom Handler'

    def _dynamic_lines_generator(self, report, options, all_column_groups_expression_totals, warnings=None):

        if not options.get('show_full_hierarchy'):
            return []

        lines = []

        parent_view_accounts = self.env['account.account'].search([
            ('parent_id', '=', False),
            ('account_type', '=', 'view'),
        ], order='code, name')

        for parent in parent_view_accounts:
            has_children = len(parent.child_ids) > 0

            parent_line = self._get_account_line(
                report,
                options,
                parent,
                all_column_groups_expression_totals,
                is_parent=has_children,
                level=0
            )

            if parent_line:
                lines.append((0, parent_line))

                if parent_line.get('unfolded', False) and has_children:
                    child_lines = self._get_children_lines_recursive(
                        report,
                        options,
                        parent,
                        all_column_groups_expression_totals,
                        level=1
                    )
                    for child_line in child_lines:
                        lines.append((0, child_line))

        orphan_accounts = self.env['account.account'].search([
            ('parent_id', '=', False),
            ('account_type', '!=', 'view'),
        ], order='code, name')

        for orphan in orphan_accounts:
            orphan_line = self._get_account_line(
                report,
                options,
                orphan,
                all_column_groups_expression_totals,
                is_parent=False,
                level=0
            )

            if orphan_line:
                lines.append((0, orphan_line))

        return lines

    def _get_children_lines_recursive(self, report, options, parent_account, all_column_groups_expression_totals, level=1):
        lines = []

        children = self.env['account.account'].search([
            ('parent_id', '=', parent_account.id)
        ], order='code, name')

        for child in children:
            has_children = len(child.child_ids) > 0

            child_line = self._get_account_line(
                report,
                options,
                child,
                all_column_groups_expression_totals,
                is_parent=has_children,
                level=level
            )

            if child_line:
                lines.append(child_line)

                if child_line.get('unfolded', False) and has_children:
                    grandchildren = self._get_children_lines_recursive(
                        report,
                        options,
                        child,
                        all_column_groups_expression_totals,
                        level=level + 1
                    )
                    lines.extend(grandchildren)

        return lines

    def _report_expand_unfoldable_line_with_groupby(self, line_dict_id, groupby, options, progress, offset, unfold_all_batch_data=None):

        return {
            'lines': [],
            'offset_increment': 0,
            'has_more': False,
        }


    def _get_account_line(self, report, options, account, all_column_groups_expression_totals, is_parent=False,
                          level=0):

        columns = []
        for column in options['columns']:
            col_group_key = column.get('column_group_key')
            expression_totals = all_column_groups_expression_totals.get(col_group_key, {})
            col_value = self._compute_account_balance(account, options, column, expression_totals)

            columns.append(report._build_column_dict(
                col_value,
                column,
                options=options
            ))

        line_id = report._get_generic_line_id('account.account', account.id)
        has_children = len(account.child_ids) > 0

        line = {
            'id': line_id,
            'name': f"{account.code} {account.name}",
            'level': level + 2,
            'columns': columns,
            'account_id': account.id,
            'caret_options': 'account.account',
        }

        if has_children:
            line['unfoldable'] = True
            line['unfolded'] = line_id in options.get('unfolded_lines', [])
            line['expand_function'] = '_report_expand_unfoldable_line_with_groupby'
        else:
            line['unfoldable'] = False
            line['unfolded'] = False

        return line

    def _compute_account_balance(self, account, options, column, expression_totals):

        if account.account_type == 'view':
            children = self.env['account.account'].search([
                ('parent_path', '=like', f'{account.parent_path}%'),
                ('id', '!=', account.id),
                ('account_type', '!=', 'view')
            ])

            total = 0
            for child in children:
                child_balance = self._get_actual_balance(child, options, column)
                total += child_balance

            return total
        else:
            return self._get_actual_balance(account, options, column)

    def _get_actual_balance(self, account, options, column):

        domain = [
            ('account_id', '=', account.id),
            ('parent_state', '=', 'posted'),
        ]

        if options.get('date'):
            date_from = options['date'].get('date_from')
            date_to = options['date'].get('date_to')

            if date_from:
                domain.append(('date', '>=', date_from))
            if date_to:
                domain.append(('date', '<=', date_to))

        aml_results = self.env['account.move.line'].read_group(
            domain,
            ['debit:sum', 'credit:sum', 'balance:sum'],
            []
        )

        if aml_results:
            expr_label = column.get('expression_label', 'balance')
            return aml_results[0].get(expr_label, 0)

        return 0
