<script>
    class MovimientosTable {
        props
        columns
        constructor({ids, eventHandler}) {
            this.props = {
                ids,
                eventHandler,
                movimientos: [],
                formatters: {
                    number: new Intl.NumberFormat('es-CL'),
                    date: new Intl.DateTimeFormat('es-CL', {
                        day: '2-digit',
                        month: '2-digit',
                        year: 'numeric'
                    }),
                },
            }

            this.columns = [
                {title: 'Sigla', defs: {width: 'short', type: 'string'}, process: movimiento => movimiento.cuenta.inmobiliaria.sigla, args: ['movimiento'], searchable: true, export: true}, //0
                {title: 'Banco', defs: {width: 'long', type: 'string'}, process: movimiento => movimiento.cuenta.banco.nombre, args: ['movimiento'], searchable: true, export: true},
                {title: 'Cuenta', defs: {width: 'short', type: 'string'}, process: movimiento => movimiento.cuenta.cuenta, args: ['movimiento'], searchable: true, export: true},
                {title: 'Fecha', defs: {width: 'long', type: 'string'}, process: fecha => this.props.formatters.date.format(fecha), args: ['fecha'], searchable: true, export: true, format: (value) => value.split('-').reverse().join('-')},
                {title: 'ISO Fecha', defs: {visible: false}, process: fecha => [fecha.getFullYear(), fecha.getMonth() + 1, fecha.getDate()].join('-'), args: ['fecha']},
                {title: 'Mes', defs: {width: 'short', type: 'string'}, process: fecha => fecha.getMonth() + 1, args: ['fecha'], searchable: true}, //5
                {title: 'Año', defs: {width: 'long', type: 'string'}, process: fecha => fecha.getFullYear(), args: ['fecha'], searchable: true},
                {title: 'Valor', defs: {className: 'dt-right', width: 'long', type: 'num'}, process: valor => this.props.formatters.number.format(valor), args: ['valor'], export: true, format: (value) => value.replace(/\./g, '')},
                {title: 'ISO Valor', defs: {visible: false, type: 'num'}, args: ['valor']},
                {title: 'Glosa', defs: {width: 'short', type: 'string'}, process: movimiento => movimiento.glosa, args: ['movimiento'], export: true},
                {title: 'Centro de Costo', defs: {width: 'short', type: 'string'}, process: movimiento => (movimiento.detalles && movimiento.detalles.centro_costo) ? movimiento.detalles.centro_costo.id : '', args: ['movimiento'], searchable: true, export: true}, //10
                {title: 'Categoría', defs: {width: 'short', type: 'string'}, process: movimiento => (movimiento.detalles) ? movimiento.detalles.categoria : '', args: ['movimiento'], searchable: true, export: true},
                {title: 'Detalle', defs: {width: 'long', type: 'string'}, process: movimiento => (movimiento.detalles) ? movimiento.detalles.detalle : '', args: ['movimiento'], export: true},
                {title: 'RUT', defs: {width: 'short', type: 'string'}, process: movimiento => (movimiento.detalles && movimiento.detalles.digito) ? `${this.props.formatters.number.format(movimiento.detalles.rut)}-${movimiento.detalles.digito}` : '', args: ['movimiento'], searchable: true, export: true},
                {title: 'Nombre', defs: {width: 'short', type: 'string'}, args: ['nombre'], searchable: true, export: true},
                {title: 'Identificador', defs: {width: 'short', type: 'string'}, process: movimiento => (movimiento.detalles) ? movimiento.detalles.identificador : '', args: ['movimiento'], export: true}, //15
                {title: 'Editar', defs: {width: 'short', type: 'string'}, args: ['buttonsHTML']},
            ]
            const N = this.columns.filter(column => typeof column.defs.visible === 'undefined' || column.defs.visible).length
            const nShort = this.columns.filter(column => column.defs.width === 'short').length
            const nLong = this.columns.filter(column => column.defs.width === 'long').length
            const short = `${(nShort / N).toFixed(2)}%`
            const long = `${(nLong / N).toFixed(2)}%`

            this.columns = this.columns.map(column => {
                if (typeof column.defs.width === 'undefined') {
                    return column
                }
                switch (column.defs.width) {
                    case 'short':
                        column.defs.width = short
                        break
                    case 'long':
                        column.defs.width = long
                        break
                }
                return column
            })

            const tr = $(this.props.ids.table).find('thead tr')
            tr.empty()
            this.columns.forEach(column => {
                if (typeof column.defs.className === 'undefined') {
                    tr.append(`<th>${column.title}</th>`)
                    return
                }
                switch (column.defs.className) {
                    case 'dt-right':
                        tr.append(`<th class="right aligned">${column.title}</th>`)
                        break
                    case 'dt-center':
                        tr.append(`<th class="center aligned">${column.title}</th>`)
                        break
                    default:
                        tr.append(`<th>${column.title}</th>`)
                        break
                }
            })

            let dtD = structuredClone(datatables_defaults)
            const groupedColumns = Object.groupBy(this.columns, ({defs}) => Object.entries(defs).map((field, value) => `${field}: ${value}`).join(' - '))
            const columnDefs = Object.values(groupedColumns).map(group => {
                return {
                    targets: group.map(({title}) => title).map(title => this.columns.map(column => column.title).indexOf(title)),
                    ...group[0].defs
                }
            })
            const searchBuilderColumns = this.columns.filter(column => column.searchable)
                .map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
            const exportColumns = this.columns.filter(column => column.export)
                .map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
            const order = ['Sigla', 'Banco', 'ISO Fecha'].map(title => {
                return [this.columns.map(column => column.title).indexOf(title), 'asc']
            })
            dtD = Object.assign(dtD, {
                columnDefs,
                order,
                language: Object.assign(dtD.language, {
                    searchBuilder
                }),
                layout: {
                    top1: {
                        searchBuilder: {
                            columns: searchBuilderColumns,
                        }
                    },
                    top1End: {
                        buttons: [
                            {
                                extend: 'excelHtml5',
                                className: 'green',
                                text: 'Exportar a Excel <i class="file excel icon"></i>',
                                title: 'Movimientos Contables',
                                download: 'open',
                                exportOptions: {
                                    columns: exportColumns,
                                    format: {
                                        body: (data, row, columnIdx, node) => {
                                            const formats = this.columns.filter(columnDef => columnDef.format)
                                            const match = formats.map(({title}) => title).indexOf(this.columns[columnIdx].title)
                                            if (match > -1) {
                                                return formats[match].format(data)
                                            }
                                            if (typeof data === 'string' && data.includes('<span data-tooltip')) {
                                                return data.replace(/<span data-tooltip="(.*)">(.*)<\/span>/, '$2')
                                            }
                                            return data
                                        }
                                    }
                                },
                                customize: xlsx => {
                                    const sheet = xlsx.xl.worksheets['sheet1.xml']
                                    const columns = Object.values($('row[r="2"] t', sheet).map((idx, column) => column.textContent))
                                    const columnStylesMap = {
                                        Valor: '63',
                                        Fecha: '15'
                                    }
                                    Object.entries(columnStylesMap).forEach((column, style) => {
                                        const columnIndex = String.fromCharCode('A'.charCodeAt(0) + columns.indexOf(column))
                                        $(`c[r^="${columnIndex}"]`, sheet).attr('s', style)
                                    })
                                }
                            }
                        ]
                    }
                },
                data: this.props.movimientos,
                rowCallback: (row, data) => {
                    $(row).find(this.props.ids.buttons.edit).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.edit().movimiento)
                    $(row).find(this.props.ids.buttons.remove).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.remove().movimiento)
                }
            })
            this.props.table = new DataTable(this.props.ids.table, dtD)
        }
        draw() {
            return {
                table: (movimientos) => {
                    const info = this.props.table.page.info()
                    this.props.table.clear().rows.add(this.draw().movimientos(movimientos)).draw()
                    this.props.table.page(info.page).draw(false)
                    $(this.props.ids.buttons.edit).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.edit().movimiento)
                    $(this.props.ids.buttons.remove).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.remove().movimiento)
                },
                movimientos: (movimientos) => {
                    const output = []
                    movimientos.forEach(movimiento => {
                        this.draw().movimiento({movimiento, output})
                    })
                    return output
                },
                movimiento: ({movimiento, output}) => {
                    const valor = movimiento.abono - movimiento.cargo
                    const fecha = movimiento.fecha

                    const buttons = {
                        edit: {
                            icon: 'edit'
                        },
                        remove: {
                            color: ' red',
                            icon: 'trash'
                        }
                    }
                    const buttonsHTML = Object.entries(buttons).map(([action, {color='', icon}]) => {
                        const className = this.props.ids.buttons[action].replace('.', '')
                        return `<button class="ui${color} icon button ${className}" data-id="${movimiento.id}" data-index="${movimiento.index}" data-type="movimiento"><i class="${icon} icon"></i></button>`
                    }).join('')

                    let nombre = ''
                    if (movimiento.detalles) {
                        if (movimiento.detalles.relacionado) {
                            let type = movimiento.detalles.relacionadoType
                            type = type.charAt(0).toUpperCase() + type.slice(1)
                            nombre = `<span data-tooltip="${type}">${movimiento.detalles.nombres}</span>`
                        } else {
                            nombre = movimiento.detalles.nombres
                        }
                    }

                    const params = {
                        movimiento,
                        fecha,
                        valor,
                        nombre,
                        buttonsHTML,
                    }

                    const data = {}
                    this.columns.forEach(column => {
                        if (column.process) {
                            const args = Object.entries(params).filter(([param, value]) => column.args.includes(param)).map(arr => arr[1])
                            data[column.title] = column.process(...args)
                            return
                        }
                        if (column.args) {
                            data[column.title] = Object.entries(params).filter(([param, value]) => column.args.includes(param)).map(arr => arr[1])[0]
                            return;
                        }
                        data[column.title] = params[column.title.toLowerCase()]
                    })

                    const values = []
                    this.columns.forEach(column => {
                        values.push(data[column.title])
                    })
                    output.push(values)
                }
            }
        }
    }
</script>
