import ast

from odoo import models

# Journal types that represent liquidity accounts (bank, cash, credit card)
LIQUIDITY_JOURNAL_TYPES = ('bank', 'cash', 'credit')


class AccountJournal(models.Model):
    """Extends account.journal to add bank reconciliation dashboard actions.

    Provides methods that link the journal dashboard cards to the
    bank reconciliation widget and related views, enabling quick
    navigation from the Accounting dashboard.
    """

    _inherit = 'account.journal'

    # -------------------------------------------------------------------------
    # Reconciliation actions
    # -------------------------------------------------------------------------

    def action_open_reconcile(self):
        """Open the appropriate reconciliation view for this journal.

        For liquidity journals (bank / cash / credit), opens the bank
        reconciliation widget filtered to show only unmatched statement
        lines belonging to this journal.

        For all other journal types (sale, purchase, general …), opens
        the list of posted but unreconciled journal items so the user
        can manually reconcile them.

        Returns:
            dict: A window action descriptor.
        """
        self.ensure_one()

        if self.type in LIQUIDITY_JOURNAL_TYPES:
            reconcile_ctx = {
                'default_journal_id': self.id,
                'search_default_journal_id': self.id,
                'search_default_not_matched': True,
            }
            stmt_line_model = self.env['account.bank.statement.line']
            return stmt_line_model._action_open_bank_reconciliation_widget(
                default_context=reconcile_ctx,
            )

        # Non-liquidity journals: show unreconciled move lines
        xml_ref = 'fusion_accounting.action_move_line_posted_unreconciled'
        return self.env['ir.actions.act_window']._for_xml_id(xml_ref)

    def action_open_to_check(self):
        """Open bank reconciliation showing only items flagged for review.

        Navigates to the bank reconciliation widget with the
        *to check* search filter enabled so the user sees only
        statement lines that were flagged during import or matching.

        Returns:
            dict: A window action descriptor.
        """
        self.ensure_one()

        review_ctx = {
            'default_journal_id': self.id,
            'search_default_journal_id': self.id,
            'search_default_to_check': True,
        }
        stmt_line_model = self.env['account.bank.statement.line']
        return stmt_line_model._action_open_bank_reconciliation_widget(
            default_context=review_ctx,
        )

    def action_open_bank_transactions(self):
        """Open a flat list of all bank transactions for this journal.

        Unlike the default kanban-first reconciliation view, this
        method forces the list view to appear first, giving the user
        a tabular overview of every transaction.

        Returns:
            dict: A window action descriptor.
        """
        self.ensure_one()

        txn_ctx = {
            'default_journal_id': self.id,
            'search_default_journal_id': self.id,
        }
        stmt_line_model = self.env['account.bank.statement.line']
        return stmt_line_model._action_open_bank_reconciliation_widget(
            default_context=txn_ctx,
            kanban_first=False,
        )

    def action_open_reconcile_statement(self):
        """Open bank reconciliation for a single statement.

        The target statement id is expected in the environment context
        under the key ``statement_id``.  This is typically set by a
        button on the bank statement form or dashboard.

        Returns:
            dict: A window action descriptor.
        """
        target_statement_id = self.env.context.get('statement_id')
        stmt_ctx = {
            'search_default_statement_id': target_statement_id,
        }
        stmt_line_model = self.env['account.bank.statement.line']
        return stmt_line_model._action_open_bank_reconciliation_widget(
            default_context=stmt_ctx,
        )

    # -------------------------------------------------------------------------
    # Dashboard open_action override
    # -------------------------------------------------------------------------

    def open_action(self):
        """Route the dashboard click to the bank reconciliation widget.

        When the user clicks on a liquidity journal card in the
        Accounting dashboard and no specific ``action_name`` has been
        provided in the context, redirect to the bank reconciliation
        widget filtered for this journal's default account.

        For every other case the standard behaviour is preserved by
        delegating to ``super()``.

        Returns:
            dict: A window action descriptor.
        """
        is_liquidity = self.type in LIQUIDITY_JOURNAL_TYPES
        has_explicit_action = self.env.context.get('action_name')

        if is_liquidity and not has_explicit_action:
            self.ensure_one()
            account_filter = [
                ('line_ids.account_id', '=', self.default_account_id.id),
            ]
            widget_ctx = {
                'default_journal_id': self.id,
                'search_default_journal_id': self.id,
            }
            stmt_line_model = self.env['account.bank.statement.line']
            return stmt_line_model._action_open_bank_reconciliation_widget(
                extra_domain=account_filter,
                default_context=widget_ctx,
            )

        return super().open_action()

    # -------------------------------------------------------------------------
    # Dashboard data helpers
    # -------------------------------------------------------------------------

    def _fill_general_dashboard_data(self, dashboard_data):
        """Augment general-journal dashboard data with tax periodicity flag.

        For journals of type *general*, adds the boolean key
        ``is_account_tax_periodicity_journal`` that indicates whether
        the journal is the company's designated tax-closing journal.

        Args:
            dashboard_data (dict): Mapping of journal id -> dashboard
                data dict, mutated in place.
        """
        super()._fill_general_dashboard_data(dashboard_data)

        general_journals = self.filtered(lambda j: j.type == 'general')
        for jrnl in general_journals:
            tax_journal = jrnl.company_id._get_tax_closing_journal()
            is_tax_periodicity = jrnl == tax_journal
            dashboard_data[jrnl.id]['is_account_tax_periodicity_journal'] = is_tax_periodicity

    # -------------------------------------------------------------------------
    # General Ledger shortcut
    # -------------------------------------------------------------------------

    def action_open_bank_balance_in_gl(self):
        """Open the General Ledger report pre-filtered to this journal's bank account.

        Loads the General Ledger action and injects the default
        account code filter so the report immediately displays
        only the lines relevant to the journal's primary account.

        Returns:
            dict: A window action descriptor for the General Ledger report.
        """
        self.ensure_one()

        gl_action_ref = 'fusion_accounting.action_account_report_general_ledger'
        gl_action = self.env['ir.actions.actions']._for_xml_id(gl_action_ref)

        # Merge the account filter into the existing action context
        existing_ctx = ast.literal_eval(gl_action.get('context', '{}'))
        existing_ctx['default_filter_accounts'] = self.default_account_id.code
        gl_action['context'] = existing_ctx

        return gl_action
