@extends('layout.base')

@push('page_styles')
    <style>
        #data {
            margin-left: 1rem;
            margin-right: 1rem;
        }
    </style>
@endpush

@section('page_content')
    <div class="ui container">
        <h2 class="ui header">Matriz Facturación</h2>
        <h4 class="ui dividing header">
            <div class="ui two column grid">
                <div id="list_title" class="column">Proyectos</div>
                <div class="right aligned column">
                    <div class="ui tiny icon buttons">
                        <button id="up_button" class="ui button">
                            <i class="up arrow icon"></i>
                        </button>
                        <button id="refresh_button" class="ui button">
                            <i class="refresh icon"></i>
                        </button>
                    </div>
                </div>
            </div>
        </h4>
        <div id="proyectos" class="ui link selection list">
            @foreach ($proyectos as $proyecto)
                <div class="item" data-proyecto="{{$proyecto->id}}">{{$proyecto->descripcion}}</div>
            @endforeach
        </div>
    </div>
    <div id="data"></div>
@endsection

@include('layout.head.styles.datatables')
@include('layout.body.scripts.datatables')

@push('page_scripts')
    <script>
        const money = {
            data: {
                ufs: {},
                ipcs: {}
            },
            ufs: {},
            ipcs: {},
            sent: {
                uf: {},
                ipc: {}
            },
            queue: {
                size: 0,
                array: () => {
                    const array = []
                    Object.entries(money.queue).forEach(([type, dates]) => {
                        if (['uf', 'ipc'].includes(type) === false) {
                            return
                        }
                        if (type === 'uf') {
                            Object.entries(dates).forEach(([dateString, ventas]) => {
                                const temp = []
                                ventas.forEach(venta => {
                                    temp.push(venta)
                                })
                                array.push({
                                    type,
                                    date: dateString,
                                    ventas: temp
                                })
                            })
                            return
                        }
                        Object.entries(dates).forEach(([dateString, data]) => {
                            const temp = []
                            data.ventas.forEach(venta => {
                                temp.push(venta)
                            })
                            array.push({
                                type,
                                start: data.start,
                                end: data.end,
                                ventas: temp
                            })
                        })
                    })
                    return array
                }
            },
            enqueue() {
                return {
                    uf: ({date, venta_id}) => {
                        const type = 'uf'
                        const data = {
                            date: [date.getFullYear(), date.getMonth()+1, date.getDate()].join('-'),
                        }
                        if (!(type in this.queue)) {
                            this.queue[type] = {}
                        }
                        if (!(data.date in this.queue[type])) {
                            this.queue[type][data.date] = []
                        }
                        if (this.queue[type][data.date].includes(data)) {
                            return
                        }
                        this.queue[type][data.date].push(venta_id)
                        this.queue['size'] ++
                    },
                    ipc: ({start, end, venta_id}) => {
                        const type = 'ipc'
                        let mult = 1
                        if (start > end) {
                            mult = -1
                            let temp = end
                            end = start
                            start = temp
                        }
                        const data = {
                            start: [start.getFullYear(), start.getMonth()+1, start.getDate()].join('-'),
                            end: [end.getFullYear(), end.getMonth()+1, end.getDate()].join('-'),
                        }
                        if (!(type in this.queue)) {
                            this.queue[type] = {}
                        }
                        if (!([data.start, data.end].join('|') in this.queue[type])) {
                            this.queue[type][[data.start, data.end].join('|')] = {
                                start: data.start,
                                end: data.end,
                                ventas: []
                            }
                        }
                        if (this.queue[type][[data.start, data.end].join('|')].ventas.includes(data)) {
                            return
                        }
                        this.queue[type][[data.start, data.end].join('|')].ventas.push({venta_id, mult})
                        this.queue['size'] ++
                    },
                }
            },
            get() {
                return {
                    many: () => {
                        const url = '{{$urls->api}}/money/many'
                        const method = 'post'
                        const chunkSize = 100
                        const promises = []
                        for (let i = 0; i < this.queue.size; i += chunkSize) {
                            const chunk = this.queue.array().slice(i, i + chunkSize)
                            const missing = chunk.filter(data => {
                                if (data.type === 'uf') {
                                    return !(data.date in this.data.ufs)
                                }
                                if (data.type === 'ipc') {
                                    const dateKey = [data.start, data.end].join('|')
                                    return !(dateKey in this.data.ipcs)
                                }
                            })
                            if (missing.length === 0) {
                                continue
                            }
                            const body = new FormData()
                            body.set('dates', JSON.stringify(missing))
                            const options = {
                                method,
                                body
                            }
                            promises.push(fetchAPI(url, options).then(response => {
                                if (!response) {
                                    return
                                }
                                return response.json().then(json => {
                                    json.values.forEach(data => {
                                        if (data.type === 'uf') {
                                            this.data.ufs[data.date] = data.value
                                        }
                                        if (data.type === 'ipc') {
                                            const dateKey = [data.start, data.end].join('|')
                                            this.data.ipcs[dateKey] = data.value
                                        }
                                    })
                                    return json.values
                                })
                            }))
                        }
                        return Promise.all(promises)
                    }
                }
            }
        }

        class Unidad {
            id
            tipo
            descripcion
            prorrateo
            precio

            constructor({id, tipo, descripcion, prorrateo, precio}) {
                this.id = id
                this.tipo = tipo
                this.descripcion = descripcion
                this.prorrateo = prorrateo
                this.precio = precio
            }
        }
        class Venta {
            id
            precio
            fecha
            escritura
            uf
            ipc
            unidades
            principal

            constructor({id, precio, fecha, escritura, unidades, principal}) {
                this.id = id
                this.precio = precio
                this.fecha = new Date(fecha)
                this.escritura = new Date(escritura)
                this.unidades = unidades
                this.principal = principal
            }

            draw({tbody, valor_terreno}) {
                /**
                 'Venta',
                 'Unidades',
                 'Tipo',
                 'Unidad',
                 'Fecha Promesa',
                 'Valor Promesa',
                 'Prorrateo',
                 'Descuento',
                 'Precio Venta',
                 'Precio Bruto',
                 'IVA',
                 'Precio Neto',
                 '% IVA/Neto',
                 'Fecha Escritura',
                 'UF',
                 'IPC'
                 */
                const dateFormatter = new Intl.DateTimeFormat('es-CL', {year: 'numeric', month: 'numeric', day: 'numeric'})
                const pesosFormatter = new Intl.NumberFormat('es-CL', {style: 'currency', currency: 'CLP'})
                const ufFormatter = new Intl.NumberFormat('es-CL', {minimumFractionDigits: 2, maximumFractionDigits: 2})
                const venta = this.principal.descripcion
                const cantidad = this.unidades.length
                this.unidades.forEach(unidad => {
                    const valor = (unidad.valor > 0) ? unidad.valor : unidad.precio
                    const values = [
                        '<a href="{{$urls->base}}/ventas/factura/' + this.id + '">' + venta + '</a>',
                        cantidad,
                        unidad.tipo,
                        unidad.descripcion,
                        dateFormatter.format(this.fecha),
                        ufFormatter.format(valor) + ' UF',
                        unidad.prorrateo,
                        '',
                        '',
                        '',
                        '',
                        '',
                        '',
                        '',
                        '',
                        ''
                    ]
                    if (this.escritura !== null) {
                        const ipc = (this.ipc >= 0) ? (1 + this.ipc) : 1 / (1 + this.ipc)
                        const descuento = valor_terreno * ipc * unidad.prorrateo
                        const precio_venta = valor * this.uf
                        const precio_bruto = precio_venta - descuento
                        const precio_neto = precio_bruto / 1.19
                        const iva = precio_bruto - precio_neto

                        let i = 7
                        values[i++] = (!isNaN(descuento)) ? pesosFormatter.format(descuento) : '<div class="ui active inline loader"></div>'
                        values[i++] = (!isNaN(precio_venta)) ? pesosFormatter.format(precio_venta) : ''
                        values[i++] = (!isNaN(precio_bruto)) ? pesosFormatter.format(precio_bruto) : ''
                        values[i++] = (!isNaN(iva)) ? pesosFormatter.format(iva) : ''
                        values[i++] = (!isNaN(precio_neto)) ? pesosFormatter.format(precio_neto) : ''
                        values[i++] = (!isNaN(iva) && !isNaN(precio_venta)) ? (iva / precio_venta * 100).toFixed(2) + '%' : ''
                        values[i++] = dateFormatter.format(this.escritura)
                        values[i++] = (!isNaN(this.uf)) ? ufFormatter.format(this.uf) : ''
                        values[i++] = (!isNaN(this.ipc)) ? (ufFormatter.format(this.ipc >= 0 ? this.ipc * 100 : -this.ipc * 100) + '%') : ''
                    }
                    const row = $('<tr></tr>')
                    values.forEach(value => {
                        row.append(
                            $('<td></td>').html(value)
                        )
                    })
                    tbody.append(row)
                })
            }
        }
        const proyectos = {
            ids: {},
            selected: 0,
            data: JSON.parse('{!! json_encode($proyectos) !!}'),
            sent: false,
            queues: {
                uf: {},
                ipc: {}
            },
            ufs: {},
            ipcs: {},
            table: null,
            get: function() {
                return {
                    ventas: () => {
                        if (this.sent) {
                            return
                        }
                        this.sent = true
                        const url = '{{$urls->api}}/ventas/facturacion/proyecto/' + this.selected
                        this.draw().loading()
                        return fetchAPI(url).then(response => {
                            if (!response) {
                                return
                            }
                            return response.json().then(json => {
                                const idx = this.data.findIndex(proyecto => proyecto.id === json.proyecto_id)
                                this.data[idx]['ventas'] = []
                                const ventas = []
                                const chunkSize = 100
                                for (let i = 0; i < json.ventas.length; i += chunkSize) {
                                    const chunk = json.ventas.slice(i, i + chunkSize).map(venta => venta.id)
                                    ventas.push(this.get().chunk({idx, chunk}))
                                }
                                Promise.all(ventas).then(() => {
                                    this.draw().ventas(idx)
                                    this.sent = false
                                    money.get().many().then(response => {
                                        response.forEach(dates => {
                                            dates.forEach(values => {
                                                values.ventas.forEach(venta => {
                                                    let vidx = 0
                                                    if (values.type === 'uf') {
                                                        vidx = this.data[idx].ventas.findIndex(v => v.id === venta)
                                                        this.data[idx].ventas[vidx].uf = values.value
                                                        return
                                                    }
                                                    if (values.type === 'ipc') {
                                                        vidx = this.data[idx].ventas.findIndex(v => v.id === venta.venta_id)
                                                        this.data[idx].ventas[vidx].ipc = values.value * venta.mult
                                                    }
                                                })
                                            })
                                        })
                                        this.draw().ventas(idx)
                                    })
                                })
                            })
                        })
                    },
                    chunk: ({idx, chunk}) => {
                        const url = '{{$urls->api}}/ventas/facturacion/get'
                        const method = 'post'
                        const body = new FormData()
                        body.set('ventas', chunk)

                        return fetchAPI(url, {method, body}).then(response => {
                            if (!response) {
                                return response
                            }
                            return response.json().then(json => {
                                json.ventas.forEach(venta => {
                                    this.add().venta({proyecto_idx: idx, venta})
                                })
                            });
                        })
                    },
                }
            },
            add() {
                return {
                    venta: ({proyecto_idx, venta}) => {
                        const v = new Venta(venta)
                        this.data[proyecto_idx].ventas.push(v)
                        const fecha_terreno = (typeof this.data[proyecto_idx].terreno.fecha === 'undefined') ? new Date() : new Date(this.data[proyecto_idx].terreno.fecha)

                        if (v.escritura !== null) {
                            money.enqueue().uf({date: v.escritura, venta_id: v.id})
                            money.enqueue().ipc({start: v.escritura, end: fecha_terreno, venta_id: v.id})
                        }
                    },
                }
            },
            register() {
                return {
                    uf: ({dateString, venta_id}) => {
                        if (!Object.hasOwn(this.queues.uf, dateString)) {
                            this.queues.uf[dateString] = []
                        }
                        this.queues.uf[dateString].push(venta_id)
                    },
                    ipc: ({dateString, venta_id}) => {
                        if (!Object.hasOwn(this.queues.ipc, dateString)) {
                            this.queues.ipc[dateString] = []
                        }
                        this.queues.ipc[dateString].push(venta_id)
                    }
                }
            },
            draw: function() {
                return {
                    proyectos: () => {
                        $(this.ids.title).html('Proyectos')
                        if (this.table !== null) {
                            this.table.clear()
                            this.table.destroy()
                            $(this.ids.data).html('')
                        }
                        $(this.ids.data).hide()
                        $(this.ids.proyectos).find('.item').css('cursor', 'pointer')
                        $(this.ids.proyectos).show()
                    },
                    ventas: proyecto_idx => {
                        $(this.ids.title).html(this.data[proyecto_idx].descripcion)
                        const parent = $(this.ids.data)
                        if (this.table !== null) {
                            this.table.clear()
                            this.table.destroy()
                            this.table = null
                            parent.html('')
                        }
                        const table = $('<table></table>').addClass('ui compact table')
                        table.append(this.draw().thead())
                        table.append(this.draw().tbody(proyecto_idx))
                        parent.show()
                        parent.html(table)
                        $(this.ids.proyectos).hide()
                        if (this.table === null) {
                            const dtD = structuredClone(datatables_defaults)
                            dtD['pageLength'] = 100
                            dtD['order'] = [[0, 'asc']]
                            this.table = table.DataTable(dtD)
                        }
                    },
                    thead: () => {
                        const thead = $('<thead></thead>')
                        const columns = [
                            'Venta',
                            'Unidades',
                            'Tipo',
                            'Unidad',
                            'Fecha Promesa',
                            'Valor Promesa',
                            'Prorrateo',
                            'Descuento',
                            'Precio Venta',
                            'Precio Bruto',
                            'IVA',
                            'Precio Neto',
                            '% IVA/Neto',
                            'Fecha Escritura',
                            'UF',
                            'IPC'
                        ]
                        const row = $('<tr></tr>')
                        columns.forEach(title => {
                            row.append(
                                $('<th></th>').html(title)
                            )
                        })
                        thead.append(row)
                        return thead
                    },
                    tbody: proyecto_idx => {
                        const tbody = $('<tbody></tbody>')
                        this.data[proyecto_idx].ventas.forEach(venta => {
                            venta.draw({tbody, valor_terreno: this.data[proyecto_idx].terreno.valor})
                        })
                        return tbody
                    },
                    loading: () => {
                        $(this.ids.proyectos).find('.item').css('cursor', 'wait')
                    }
                }
            },
            actions: function() {
                return {
                    up: event => {
                        this.draw().proyectos()
                    },
                    refresh: event => {
                        const list = $(this.ids.proyectos)
                        if (list.is(':hidden')) {
                            const table = $(this.ids.table)
                            table.hide()
                            if (this.table !== null) {
                                this.table.clear().destroy()
                                this.table = null
                            }
                            this.get().ventas()
                        } else {
                            this.draw().proyectos()
                        }
                    }
                }
            },
            setup: function({ids}) {
                this.ids = ids
                $(this.ids.data).hide()
                $(this.ids.proyectos).find('.item').click(event => {
                    this.selected = $(event.currentTarget).data('proyecto')
                    this.get().ventas()
                })

                $(this.ids.buttons.up).click(this.actions().up)
                $(this.ids.buttons.refresh).click(this.actions().refresh)
            }
        }
        $(document).ready(() => {
            proyectos.setup({ids: {
                    title: '#list_title',
                    proyectos: '#proyectos',
                    data: '#data',
                    buttons: {
                        up: '#up_button',
                        refresh: '#refresh_button'
                    }
                }
            })
        })
    </script>
@endpush
