/** @odoo-module */
const { Component } = owl;
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { useRef, useState } from "@odoo/owl";
import { BlockUI } from "@web/core/ui/block_ui";
import { download } from "@web/core/network/download";
const actionRegistry = registry.category("actions");
const today = luxon.DateTime.now();
let monthNamesShort = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

class TrialBalance extends owl.Component {
    async setup() {
        super.setup(...arguments);
        this.initial_render = true;
        this.orm = useService('orm');
        this.action = useService('action');
        this.tbody = useRef('tbody');
        this.end_date = useRef('date_to');
        this.start_date = useRef('date_from');
        this.period = useRef('periods');
        this.period_year = useRef('period_year');
        this.unfoldButton = useRef('unfoldButton');
        this.state = useState({
            move_line: null,
            data: null,
            total: null,
            journals: null,
            selected_analytic: [],
            analytic_account: null,
            selected_journal_list: [],
            selected_analytic_account_rec: [],
            date_range: 'month',
            date_type: 'month',
            apply_comparison: false,
            comparison_type: null,
            date_viewed: [],
            comparison_number: null,
            options: null,
            method: {
                        'accural': true
                    },
        });
        this.load_data(self.initial_render = true);
    }
    async load_data() {
        /**
         * Loads the data for the trial balance report.
         */
        let move_line_list = []
        let move_lines_total = ''
        var self = this;
        var action_title = self.props.action.display_name;
        try {
            var self = this;
            var today = new Date();
            var startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
            var endOfMonth = new Date(today.getFullYear(), today.getMonth() + 1, 0);
            self.state.data = await self.orm.call("account.trial.balance", "view_report", []);
            self.start_date.el.value = startOfMonth.getFullYear() + '-' + String(startOfMonth.getMonth() + 1).padStart(2, '0') + '-' + String(startOfMonth.getDate()).padStart(2, '0');
            self.end_date.el.value = endOfMonth.getFullYear() + '-' + String(endOfMonth.getMonth() + 1).padStart(2, '0') + '-' + String(endOfMonth.getDate()).padStart(2, '0');
            self.state.date_viewed.push(monthNamesShort[today.getMonth()] + '  ' + today.getFullYear())
            self.state.journals = self.state.data[1]['journal_ids']
            $.each(self.state.data, function (index, value) {
                self.state.journals = value.journal_ids
            })
        }
        catch (el) {
            window.location.href;
        }
    }
    async applyFilter(val, ev, is_delete) {
        /**
         * Asynchronously applies filters and loads data for the trial balance report.
         * Modifies state variables based on the selected filter options.
         * Updates 'move_line_list' and 'move_lines_total'.
         * Sets the start and end date inputs based on selected filter options.
         * Appends the selected date ranges to 'state.date_viewed'.
         * Updates 'state.journals' based on the selected journal filter.
         * Retrieves data using the 'account.trial.balance' API with the selected filter values.
         * Updates 'state.data' with the retrieved data.
         * Handles the comparison logic and updates 'state.date_viewed' accordingly.
         * Reverses the order of 'state.date_viewed' if data exists.
         *
         * @param {any} val - The selected filter value or event.
         * @param {Event} ev - The event object triggered by the filter.
         * @param {boolean} is_delete - Flag indicating if the filter is being deleted.
         * @returns {Promise<void>} Resolves when the filter is applied and data is loaded.
         */
        if (ev && ev.target && ev.target.attributes["data-value"] && ev.target.attributes["data-value"].value == 'no comparison') {
            const lastIndex = this.state.date_viewed.length - 1;
            this.state.date_viewed.splice(0, lastIndex);
        }
        if (ev) {
            if (ev.input && ev.input.attributes.placeholder.value == 'Account' && !is_delete) {
                this.state.selected_analytic.push(val[0].id)
                this.state.selected_analytic_account_rec.push(val[0])
            } else if (is_delete) {
                let index = this.state.selected_analytic_account_rec.indexOf(val)
                this.state.selected_analytic_account_rec.splice(index, 1)
                this.state.selected_analytic = this.state.selected_analytic_account_rec.map((rec) => rec.id)
            }
        }
        else {
            if (val && val.target.name === 'start_date') {
                this.state.date_viewed = []
                this.state.date_viewed.push('From' + ' ' + this.formatDate(this.start_date.el.value) + ' ' + 'To' + ' ' + this.formatDate(this.end_date.el.value))
                this.state.date_range = {
                    ...this.state.date_range,
                    start_date: val.target.value
                };
            } else if (val && val.target.name === 'end_date') {
                this.state.date_viewed = []
                this.state.date_viewed.push('From' + ' ' + this.formatDate(this.start_date.el.value) + 'To' + ' ' + this.formatDate(this.end_date.el.value))
                this.state.date_range = {
                    ...this.state.date_range,
                    end_date: val.target.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'month') {
                this.start_date.el.value = today.startOf('month').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.endOf('month').toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push(today.monthShort + ' ' + today.c.year)
                this.state.date_type = val.target.attributes["data-value"].value
                this.state.comparison_type = this.state.date_type
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'year') {
                this.start_date.el.value = today.startOf('year').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.endOf('year').toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push(today.c.year)
                this.state.date_type = val.target.attributes["data-value"].value
                this.state.comparison_type = this.state.date_type
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'quarter') {
                this.start_date.el.value = today.startOf('quarter').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.endOf('quarter').toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push('Q' + ' ' + today.quarter)
                this.state.comparison_type = this.state.date_type
                this.state.date_type = val.target.attributes["data-value"].value
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'last-month') {
                this.start_date.el.value = today.startOf('month').minus({ days: 1 }).startOf('month').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.startOf('month').minus({ days: 1 }).toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push(today.startOf('month').minus({ days: 1 }).monthShort + ' ' + today.startOf('month').minus({ days: 1 }).c.year)
                this.state.date_type = 'month'
                this.state.comparison_type = this.state.date_type
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'last-year') {
                this.start_date.el.value = today.startOf('year').minus({ days: 1 }).startOf('year').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.startOf('year').minus({ days: 1 }).toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push(today.startOf('year').minus({ days: 1 }).c.year)
                this.state.date_type = 'year'
                this.state.comparison_type = this.state.date_type
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'last-quarter') {
                this.start_date.el.value = today.startOf('quarter').minus({ days: 1 }).startOf('quarter').toFormat('yyyy-MM-dd')
                this.end_date.el.value = today.startOf('quarter').minus({ days: 1 }).toFormat('yyyy-MM-dd')
                this.state.date_viewed = []
                this.state.date_viewed.push('Q' + ' ' + today.startOf('quarter').minus({ days: 1 }).quarter)
                this.state.date_type = 'quarter'
                this.state.comparison_type = this.state.date_type
                this.state.date_range = {
                    start_date: this.start_date.el.value,
                    end_date: this.end_date.el.value
                };
            } else if (val && val.target.attributes["data-value"].value == 'journal') {
                if (!val.target.classList.contains("selected-filter")) {
                    this.state.selected_journal_list.push(parseInt(val.target.attributes["data-id"].value, 10))
                    val.target.classList.add("selected-filter");
                } else {
                    const updatedList = this.state.selected_journal_list.filter(item => item !== parseInt(val.target.attributes["data-id"].value, 10));
                    this.state.selected_journal_list = updatedList
                    val.target.classList.remove("selected-filter");
                }
            } else if (val && val.target.attributes["data-value"].value === 'draft') {
                if (val.target.classList.contains("selected-filter")) {
                    const { draft, ...updatedAccount } = this.state.options;
                    this.state.options = updatedAccount;
                    val.target.classList.remove("selected-filter");
                } else {
                    this.state.options = {
                        ...this.state.options,
                        'draft': true
                    };
                    val.target.classList.add("selected-filter");
                }
            }else if (val.target.attributes["data-value"].value === 'cash-basis') {
                if (val.target.classList.contains("selected-filter")) {
                    const { cash, ...updatedAccount } = this.state.method;
                    this.state.method = updatedAccount;
                    val.target.classList.remove("selected-filter");
                } else {
                    this.state.method = {
                        ...this.state.method,
                        'cash': true
                    };
                    val.target.classList.add("selected-filter");
                }
            }
        }
        if (this.state.apply_comparison == true) {
            if (this.state.comparison_type == 'year') {
                this.state.date_viewed = []
                if (this.start_date.el.value) {
                    var current_year = new Date(this.start_date.el.value).getFullYear();
                    var month = new Date(this.start_date.el.value).getMonth();
                } else {
                    var current_year = new Date(today).getFullYear();
                    var month = new Date(today).getMonth()
                }
                this.state.comparison_number = this.period_year.el.value
                for (var i = this.state.comparison_number; i >= 0; i--) {
                    var date = monthNamesShort[month] + ' ' + (current_year - i);
                    this.state.date_viewed.push(date);
                }
            } else if (this.state.comparison_type == 'month') {
                this.state.date_viewed = []
                this.state.comparison_number = this.period.el.value
            } else if (this.state.comparison_type == 'quarter') {
                this.state.date_viewed = []
                this.state.comparison_number = this.period.el.value
            }
        }
        this.state.data = await this.orm.call("account.trial.balance", "get_filter_values", [this.start_date.el.value, this.end_date.el.value, this.state.comparison_number, this.state.comparison_type, this.state.selected_journal_list, this.state.selected_analytic, this.state.options,this.state.method,]);
        var date_viewed = []
        this.state.data.forEach((value, index) => {
            if (index == 'journal_ids') {
                this.state.journals = value
            }
            if (value.dynamic_date_num) {
            let iterable = Array.isArray(value.dynamic_date_num) ? value.dynamic_date_num
               : Object.values(value.dynamic_date_num);
                for (const date_num of iterable) {
                     if (!date_viewed.includes(date_num)) {
                         date_viewed.push(date_num);
                     }
                }
            }
        })
        if (date_viewed.length !== 0) {
            this.state.date_viewed = date_viewed.reverse()
        }
    }
    onPeriodChange(ev) {
        /**
         * Event handler for period change.
         * Updates the value of 'period_year' element based on the event target value.
         *
         * @param {Event} ev - Event object triggered by the period change.
         * @returns {void} No explicit return value.
         */
        this.period_year.el.value = ev.target.value
    }
    onPeriodYearChange(ev) {
        /**
         * Event handler for period year change.
         * Updates the value of 'period' element based on the event target value.
         *
         * @param {Event} ev - Event object triggered by the period year change.
         * @returns {void} No explicit return value.
         */
        this.period.el.value = ev.target.value
    }
    applyComparisonPeriod(ev) {
        /**
         * Applies a comparison period and triggers data filtering.
         * Sets 'apply_comparison' flag to true and updates 'comparison_type'.
         * Invokes 'applyFilter' method to apply filters and load data.
         *
         * @param {Event} ev - Event object triggering the comparison period application.
         * @returns {void} No explicit return value.
         */
        this.state.apply_comparison = true
        this.state.comparison_type = this.state.date_type
        this.applyFilter(null, ev)
    }
    applyComparisonYear(ev) {
        /**
         * Applies a comparison year and triggers data filtering.
         * Sets 'apply_comparison' flag to true and updates 'comparison_type' to 'year'.
         * Invokes 'applyFilter' method to apply filters and load data.
         *
         * @param {Event} ev - Event object triggering the comparison year application.
         * @returns {void} No explicit return value.
         */
        this.state.apply_comparison = true
        this.state.comparison_type = 'year'
        this.applyFilter(null, ev)
    }
    sumByKey(data, key) {
        /**
         * Calculates the sum of values in an array of objects by a specified key.
         *
         * @param {Array} data - Array of objects containing numeric values.
         * @param {string} key - The key to access the numeric value in each object.
         * @returns {number} The sum of the numeric values.
         */
        return data.reduce((acc, item) => acc + (item[key] || 0), 0);
    }
    get comparison_number_range() {
        /**
         * Generates an array of numbers representing a comparison number range.
         * The range includes numbers from 1 up to the 'comparison_number' value in the state.
         *
         * @returns {Array} An array of numbers representing the comparison number range.
         */
        const range = [];
        for (let i = 1; i <= this.state.comparison_number; i++) {
            range.push(i);
        }
        return range;
    }
    async applyComparison(ev) {
        /**
         * Disables comparison mode, resets comparison settings, and triggers data filtering.
         * Sets 'apply_comparison' flag to false and clears 'comparison_type' and 'comparison_number'.
         * Removes all date view entries except the current month/year.
         * Invokes 'applyFilter' method to apply filters and load data.
         *
         * @param {Event} ev - Event object triggering the comparison mode removal.
         * @returns {void} No explicit return value.
         */
        this.state.apply_comparison = false
        this.state.comparison_type = null
        this.state.comparison_number = null
        const lastIndex = this.state.date_viewed.length - 1;
        this.state.date_viewed.splice(0, lastIndex);
        this.applyFilter(null, ev)
    }
    getDomain() {
        return [];
    }
    async printPdf(ev) {
        /**
         * Asynchronously generates and prints a PDF report.
         * Triggers an action to generate a PDF report based on the current state and settings.
         *
         * @param {Event} ev - Event object triggering the PDF report generation.
         * @returns {Promise} A promise that resolves after the PDF report action is triggered.
         */
        ev.preventDefault();
        var self = this;
        var action_title = self.props.action.display_name;
        let comparison_number_range = self.comparison_number_range
        let data_viewed = self.state.date_viewed
        if (self.state.apply_comparison) {
             if (self.comparison_number_range.length > 10) {
                comparison_number_range = self.comparison_number_range.slice(-10);
                data_viewed = self.state.date_viewed.slice(-11);
             }
         }
        return self.action.doAction({
            'type': 'ir.actions.report',
            'report_type': 'qweb-pdf',
            'report_name': 'dynamic_accounts_report.trial_balance',
            'report_file': 'dynamic_accounts_report.trial_balance',
            'data': {
                'data': self.state.data,
                'date_viewed': data_viewed,
                'filters': this.filter(),
                'apply_comparison': self.state.apply_comparison,
                'comparison_number_range': comparison_number_range,
                'title': action_title,
                'report_name': self.props.action.display_name
            },
            'display_name': self.props.action.display_name,
        });
    }
    filter() {
    var self=this;
    let startDate, endDate;
    let startYear, startMonth, startDay, endYear, endMonth, endDay;
        if (self.state.date_range){
            const today = new Date();
            if (self.state.date_range === 'year') {
                startDate = new Date(today.getFullYear(), 0, 1);
                endDate = new Date(today.getFullYear(), 11, 31);
            } else if (self.state.date_range === 'quarter') {
                const currentQuarter = Math.floor(today.getMonth() / 3);
                startDate = new Date(today.getFullYear(), currentQuarter * 3, 1);
                endDate = new Date(today.getFullYear(), (currentQuarter + 1) * 3, 0);
            } else if (self.state.date_range === 'month') {
                startDate = new Date(today.getFullYear(), today.getMonth(), 1);
                endDate = new Date(today.getFullYear(), today.getMonth() + 1, 0);
            } else if (self.state.date_range === 'last-month') {
                startDate = new Date(today.getFullYear(), today.getMonth() - 1, 1);
                endDate = new Date(today.getFullYear(), today.getMonth(), 0);
            } else if (self.state.date_range === 'last-year') {
                startDate = new Date(today.getFullYear() - 1, 0, 1);
                endDate = new Date(today.getFullYear() - 1, 11, 31);
            } else if (self.state.date_range === 'last-quarter') {
                const lastQuarter = Math.floor((today.getMonth() - 3) / 3);
                startDate = new Date(today.getFullYear(), lastQuarter * 3, 1);
                endDate = new Date(today.getFullYear(), (lastQuarter + 1) * 3, 0);
            }
        // Get the date components for start and end dates
        if (startDate) {
        startYear = startDate.getFullYear();
        startMonth = startDate.getMonth() + 1;
        startDay = startDate.getDate();
        }
        if (endDate) {
        endYear = endDate.getFullYear();
        endMonth = endDate.getMonth() + 1;
        endDay = endDate.getDate();
        }
        }
        const selectedJournalIDs = Object.values(self.state.selected_journal_list);
        const selectedJournalNames = selectedJournalIDs.map((journalID) => {
          const journal = self.state.journals[journalID];
          return journal ? journal.name : ''; // Return the name if journal exists, otherwise an empty string
        });
        let filters = {
            'journal': selectedJournalNames,
            'account': self.state.selected_analytic_account_rec,
            'options': self.state.options,
            'comparison_type': self.state.comparison_type,
            'comparison_number_range': self.state.comparison_number,
            'start_date': null,
            'end_date': null,
        };
        // Check if start and end dates are available before adding them to the filters object
        if (startYear !== undefined && startMonth !== undefined && startDay !== undefined &&
            endYear !== undefined && endMonth !== undefined && endDay !== undefined) {
            filters['start_date'] = `${startYear}-${startMonth < 10 ? '0' : ''}${startMonth}-${startDay < 10 ? '0' : ''}${startDay}`;
            filters['end_date'] = `${endYear}-${endMonth < 10 ? '0' : ''}${endMonth}-${endDay < 10 ? '0' : ''}${endDay}`;
        }
        return filters
    }
    async print_xlsx() {
        /**
         * Asynchronously generates and downloads an XLSX report.
         * Triggers an action to generate an XLSX report based on the current state and settings,
         * and initiates the download of the generated XLSX file.
         *
         * @returns {void} No explicit return value.
         */
        var self = this;
        var action_title = self.props.action.display_name;
        var datas = {
            'data': self.state.data,
            'date_viewed': self.state.date_viewed,
            'filters': this.filter(),
            'apply_comparison': self.state.apply_comparison,
            'comparison_number_range': self.comparison_number_range,
            'title': action_title,
            'report_name': self.props.action.display_name
        }
        var action = {
            'data': {
                'model': 'account.trial.balance',
                'data': JSON.stringify(datas),
                'output_format': 'xlsx',
                'report_action': self.props.action.xml_id,
                'report_name': action_title,
            },
        };
        BlockUI;
        await download({
            url: '/xlsx_report',
            data: action.data,
            complete: () => unblockUI,
            error: (error) => self.call('crash_manager', 'rpc_error', error),
        });
    }
    async show_gl(ev) {
    /**
    * Shows the General Ledger view by triggering an action.
    *
    * @param {Event} ev - The event object triggered by the action.
    * @returns {Promise} - A promise that resolves to the result of the action.
    */
        return this.action.doAction({
            type: 'ir.actions.client',
            name: 'General Ledger',
            tag: 'gen_l',
        });
    }
    formatDate(dateString) {
    /**
     * Formats a date string in "YYYY-MM-DD" format to "DD/MM/YYYY" format.
     *
     * @param {string} dateString - The date string to be formatted.
     * @returns {string} The formatted date in "DD/MM/YYYY" format.
     */
        const date = new Date(dateString);
        const day = date.getDate().toString().padStart(2, '0');
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const year = date.getFullYear();
        return `${day}/${month}/${year}`;
    }
    gotoJournalItem(ev) {
        /**
         * Navigates to the journal items list view based on the selected event target.
         *
         * @param {Event} ev - The event object triggered by the action.
         * @returns {Promise} - A promise that resolves to the result of the action.
         */
        return this.action.doAction({
            type: "ir.actions.act_window",
            res_model: 'account.move.line',
            name: "Journal Items",
            views: [[false, "list"]],
            domain: [["account_id", "=", parseInt(ev.target.attributes["data-id"].value, 10)]],
            context: { group_by: ["account_id"] },
            target: "current",
        });
    }
}
TrialBalance.template = 'trl_b_template_new';
actionRegistry.add("trl_b", TrialBalance);
