<script lang="ts">
    import { browser } from '$app/environment'
    import { onMount, tick } from 'svelte'
    import { assets as a } from '$app/paths'
    import type { Grain } from '../../../grain-types'
    import { base } from '$app/paths'
    import { sample, chooseScale, relayout } from '../../../plot'
    export let position: { lat: number; lng: number } | undefined
    export let azimuth: number | undefined
    export let inclinaison: number | undefined
    export let puissance: number
    export let prmsFeature: boolean = false
    export let id: string = ''
    export let prms: Grain.Prm[] = []
    export let prodWeekly: number[] = []
    export let maxProd: number = 0
    export let assets = a as string
    export let server = 'https://coturnix.fr'
    let consentement = false

    function addPrm(_ev: Event) {
        prms.push({ prm: null, nom: '', prenom: '' })
        consentement = false
        prms = prms
    }

    function delPrm(_ev: Event, i: number) {
        prms.splice(i, 1)
        prms = prms
    }

    let pvgis: null | {
        inputs: {
            location: { latitude: number; longitude: number }
            mounting_system: {
                fixed: { slope: { value: number }; azimuth: { value: number } }
            }
        }
        outputs: {
            hourly: {
                time: string
                'G(i)': number
                P: number
                T2m: number
                H_sun: number
                Int: number
            }[]
        }
    } = null

    export let pvgis_loading = false
    let prm_loading = false

    let initialised = false

    $: {
        initialised && updatePlot(puissance, position, azimuth, inclinaison)
    }

    let Plotly: any

    let erreur = ''

    onMount(async () => {
        //@ts-ignore
        Plotly = await import('plotly.js-dist')
        await updatePlot(puissance, position, azimuth, inclinaison)
        initialised = true
    })

    let prt: string[] = []

    let pr: { type: string; conso: number }[] = []

    let plotStyle = ''

    let profs: Map<string, { coefs: number[]; total: number }> = new Map()

    let darkMode = false
    if (browser) {
        darkMode =
            window.matchMedia &&
            window.matchMedia('(prefers-color-scheme: dark)').matches
        window
            .matchMedia('(prefers-color-scheme: dark)')
            .addEventListener('change', (event) => {
                darkMode = !!event.matches
                redraw()
            })
    }

    let profils: Record<string, { profils: string[] }> = {
        'Résidentiel ≤6kVA': {
            profils: ['RES1-P1'],
        },

        'Résidentiel 6>kVA≤36': {
            profils: ['RES11-P1'],
        },

        'Résidentiel ≤36kVA HPHC': {
            profils: ['RES2'],
        },

        'Professionel ≤36kVA': {
            profils: ['PRO1-P1'],
        },

        'Professionnel ≤36kVA HWE': {
            profils: ['PRO1WE'],
        },

        'Professionnel ≤36kVA HPHC': {
            profils: ['PRO2'],
        },

        'Entreprise 36<kVA<250 HPHC ETE-HIV': {
            profils: ['ENT1'],
        },

        /*
           "Production hydraulique":{
           "profils":[ "PRD1-P1" ]
           },

           "Production cogénération":{
           "profils":[ "PRD2-P1" ]
           },

           "Production photovoltaïque":{
           "profils":[ "PRD3-P1" ]
           },
         */
    }

    function addProfil(_ev: Event) {
        pr.push({ type: prt[0], conso: 0 })
        pr = pr
    }

    async function delProfil(i: number) {
        pr.splice(i, 1)
        pr = pr
        await updatePlot(puissance, position, azimuth, inclinaison)
    }

    async function profile(
        name: string
    ): Promise<{ coefs: number[]; total: number }> {
        prm_loading = true
        await tick()
        let profiles = await Promise.all(
            profils[name].profils.map(async (x) => {
                let resp = await fetch(`${assets}/profiles/${x}.csv`)
                return await resp.text()
            })
        )
        prm_loading = false
        await tick()

        let annee = []
        let total = 0
        let file = 0
        for (let p of profiles) {
            let l = 0
            for (let line of p.split('\n')) {
                if (!line) {
                    continue
                }
                const col = line.split(',')
                // const week = parseInt(col[0])
                // const dow = parseInt(col[1])
                const cs = parseFloat(col[2])
                const cj = parseFloat(col[3])
                for (let i = 0; i < 48; i++) {
                    let ch = parseFloat(col[5 + i])
                    const c = cs * cj * ch
                    if (file == 0) {
                        annee.push(c)
                    } else {
                        annee[l] += c
                    }
                    total += c
                }
                l += 1
            }
            file += 1
        }
        return { coefs: annee, total }
    }

    let annee: Record<number, number[]> = {}

    async function refresh(event: SubmitEvent) {
        event.preventDefault()
        if (prms) {
            prm_loading = true
            await tick()
            const resp = await fetch(
                `${server}/api/grain/projet/${id || 'nouveau'}/prms`,
                {
                    method: 'POST',
                    body: JSON.stringify(prms),
                }
            )
            if (resp.ok) {
                annee = await resp.json()
            }
            prm_loading = false
            await tick()
        } else {
            erreur = 'La liste des PRMs est vide'
        }
        await updatePlot(puissance, position, azimuth, inclinaison)
    }

    let auto = 0
    let totalProd = 0
    let totalConso = 0
    let soleil = {
        hourly: {
            x: <string[]>[],
            y: <number[]>[],
        },
        daily: {
            x: <string[]>[],
            y: <number[]>[],
        },
        weekly: {
            x: <string[]>[],
            y: <number[]>[],
        },
        x: <string[]>[],
        y: <number[]>[],
        type: 'bar',
        line: {
            color: '#ffbf00',
            width: 1,
        },
        marker: {
            color: '#ffbf00',
            width: 1,
        },
        name: 'Production solaire',
        bucket: 1,
    }

    let somme = {
        hourly: {
            x: <string[]>[],
            y: <number[]>[],
        },
        daily: {
            x: <string[]>[],
            y: <number[]>[],
        },
        weekly: {
            x: <string[]>[],
            y: <number[]>[],
        },
        x: <string[]>[],
        y: <number[]>[],
        type: 'bar',
        line: {
            color: '#b81111',
            width: 1,
        },
        marker: {
            color: '#b81111',
            width: 1,
        },
        name: 'Consommation totale',
        bucket: 1,
    }

    async function updatePv(
        puissance: number,
        position?: { lat: number; lng: number },
        azimuth?: number,
        inclinaison?: number
    ) {
        let d = new Date()
        let min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000
        let max_t = min_t + 364 * 24 * 3600
        if (
            !pvgis ||
            (position !== undefined &&
                pvgis.inputs.location.latitude != position?.lat) ||
            (position !== undefined &&
                pvgis.inputs.location.longitude != position?.lng) ||
            (azimuth !== undefined &&
                pvgis.inputs.mounting_system.fixed.slope.value !=
                    inclinaison) ||
            (azimuth !== undefined &&
                pvgis.inputs.mounting_system.fixed.azimuth.value != azimuth)
        ) {
            pvgis_loading = true
            await tick()
            let annuelle = await fetch(`${base}/pvgis`, {
                method: 'POST',
                body: JSON.stringify({
                    lat: position?.lat,
                    lng: position?.lng,
                    azimuth,
                    inclinaison,
                }),
            })
            pvgis = await annuelle.json()
            pvgis_loading = false
            await tick()
        }
        soleil.hourly = { x: [], y: [] }
        soleil.daily = { x: [], y: [] }
        soleil.weekly = { x: [], y: [] }
        maxProd = 0
        const start = new Date(min_t * 1000)
        const janvier = new Date(start.getFullYear(), 0, 1)
        for (let t = min_t; t < max_t; t += 3600) {
            let tt = new Date(t * 1000)
            let tts = tt.toLocaleString()
            let tds = tt.toLocaleDateString()
            let pp = 0
            if (pvgis) {
                let len = pvgis.outputs.hourly.length
                let n = ((t * 1000 - janvier.getTime()) / 3600000) % len
                const pvvar = 'P'
                pp =
                    (pvgis.outputs.hourly[Math.floor(n)][pvvar] * puissance) /
                    1000
                soleil.hourly.x.push(tts)
                soleil.hourly.y.push(pp)
                if ((t - min_t) % (24 * 3600) == 0) {
                    if ((t - min_t) % (24 * 7 * 3600) == 0) {
                        if (soleil.weekly.y.length) {
                            maxProd = Math.max(
                                maxProd,
                                soleil.weekly.y[soleil.weekly.y.length - 1]
                            )
                        }
                        soleil.weekly.x.push(tds)
                        soleil.weekly.y.push(pp)
                    } else {
                        soleil.weekly.y[soleil.weekly.y.length - 1] += pp
                    }
                    soleil.daily.x.push(tds)
                    soleil.daily.y.push(pp)
                } else {
                    soleil.daily.y[soleil.daily.y.length - 1] += pp
                    soleil.weekly.y[soleil.weekly.y.length - 1] += pp
                }
            }
        }
        prodWeekly = soleil.weekly.y
    }

    async function updatePlot(
        puissance: number,
        position?: { lat: number; lng: number },
        azimuth?: number,
        inclinaison?: number
    ) {
        if (!browser) {
            return
        }

        await updatePv(puissance, position, azimuth, inclinaison)

        let annee_: Record<string, { t: number[]; y: number[]; i: number }> = {}

        let d = new Date()
        const min_t = new Date(d.getFullYear(), 0, 1).getTime() / 1000
        const max_t = min_t + 364 * 24 * 3600
        for (let [prm, r] of Object.entries(annee)) {
            let d: { t: number[]; y: number[]; i: number } = {
                t: [],
                y: [],
                i: 0,
            }
            let i = 0
            for (let t = min_t; t < max_t; t += 1800) {
                d.t.push(t)
                d.y.push(r[i] / 1000)
                i += 1
            }
            annee_[prm] = d
        }

        if (pr.length > 0) {
            for (let p of pr) {
                let d: { t: number[]; y: number[]; i: number } = {
                    t: [],
                    y: [],
                    i: 0,
                }
                let i = 0
                for (let t = min_t; t <= max_t; t += 1800) {
                    d.t.push(t)
                    let pp = profs.get(p.type)
                    if (!pp) {
                        profs.set(p.type, await profile(p.type))
                    }
                    if (pp) {
                        d.y.push((pp.coefs[i] * p.conso) / pp.total)
                    }
                    i += 1
                }
                annee_[p.type] = d
            }
        }
        let auto_ = sample(min_t, max_t, annee_, somme, soleil)
        auto = auto_.auto
        totalProd = auto_.totalProd
        totalConso = auto_.totalConso
        if (!Plotly)
            //@ts-ignore
            Plotly = await import('plotly.js-dist')

        await tick()
        redraw()
    }

    let has_plot = { has_plot: false }
    let layout = {}

    function relayout_(event: any) {
        console.log('relayout_')
        const plot = document.getElementById('plot')!
        relayout(event, plot, Plotly, layout, has_plot, soleil, somme)
    }

    function redraw() {
        const plot = document.getElementById('plot')
        if (!plot) return
        chooseScale(soleil)
        chooseScale(somme)
        let unite: string
        if (soleil.bucket == 24) {
            unite = 'kWh/jour'
        } else if (soleil.bucket == 24 * 7) {
            unite = 'kWh/semaine'
        } else {
            unite = 'kWh'
        }
        layout = {
            title: 'Autoconsommation',
            autosize: true,
            automargin: true,
            plot_bgcolor: '#fff0',
            paper_bgcolor: '#fff0',
            font: {
                color: darkMode ? '#fff' : '#000',
            },
            xaxis: {
                gridcolor: darkMode ? '#444' : '#bbb',
                ticklabeloverflow: 'allow',
                ticklabelstep: 4,
                tickangle: 45,
            },
            yaxis: {
                title: { text: unite },
                gridcolor: darkMode ? '#444' : '#bbb',
                color: darkMode ? '#fff' : '#000',
            },
            showlegend: true,
            legend: {
                xanchor: 'center',
                x: 0.5,
                y: -0.4,
                orientation: 'h',
            },
        }
        plotStyle = 'min-height:450px'
        if (has_plot.has_plot) {
            Plotly!.update(plot, [soleil, somme], layout)
        } else {
            Plotly!.newPlot(plot, [soleil, somme], layout, {
                responsive: true,
            })
            //@ts-ignore
            plot.on('plotly_relayout', relayout_)
            has_plot.has_plot = true
        }

        var dataProd = [
            {
                values: [Math.round(auto), Math.round(totalProd - auto)],
                labels: ['Autoconsommé', 'Surplus'],
                marker: { colors: ['#ffbf00dd', '#b81111dd'] },
                type: 'pie',
                sort: false,
                hole: 0.5,
            },
        ]

        var dataConso = [
            {
                values: [Math.round(auto), Math.round(totalConso - auto)],
                labels: ['Autoproduit', 'Fournisseur'],
                marker: { colors: ['#ffbf00dd', '#b81111dd'] },
                type: 'pie',
                sort: false,
                hole: 0.5,
            },
        ]

        plotStyle = 'min-height:450px'
        Plotly.react(
            'autoProd',
            dataProd,
            {
                title: "Autoconsommation sur l'année",
                font: {
                    color: darkMode ? '#fff' : '#000',
                },
                plot_bgcolor: '#fff0',
                paper_bgcolor: '#fff0',
                autosize: true,
                legend: {
                    orientation: 'h',
                },
            },
            { responsive: true }
        )
        Plotly.react(
            'autoConso',
            dataConso,
            {
                title: "Autoproduction sur l'année",
                font: {
                    color: darkMode ? '#fff' : '#000',
                },
                plot_bgcolor: '#fff0',
                paper_bgcolor: '#fff0',
                autosize: true,
                legend: {
                    orientation: 'h',
                },
            },
            { responsive: true }
        )
    }
</script>

<form method="POST" action="/api/grain" id="pdl" on:submit={refresh} />
{#if erreur}
    <div
        id="erreur"
        class="alert alert-danger fade d-flex"
        class:show={erreur}
        role="alert">
        {erreur}
        <button
            type="button"
            class="btn-close"
            style="padding:20px;margin:-16px -16px -16px auto"
            on:click={() => (erreur = '')}
            aria-label="Close" />
    </div>
{/if}
<h2 class="my-5">Profils de consommation</h2>
{#if pr.length}
    <table class="table">
        <thead
            ><tr><th /><th>Profil</th><th>Consommation annuelle</th><th /></tr
            ></thead>
        <tbody>
            {#each pr as pr, i}
                <tr>
                    <td class="px-3 align-middle">Profil</td>
                    <td>
                        <select
                            class="form-select"
                            bind:value={pr.type}
                            on:change={(_ev) =>
                                updatePlot(
                                    puissance,
                                    position,
                                    azimuth,
                                    inclinaison
                                )}>
                            {#each Object.entries(profils) as [p, _]}
                                <option value={p}>{p}</option>
                            {/each}
                        </select>
                    </td>
                    <td>
                        <input
                            type="number"
                            class="form-control"
                            placeholder="Abonnement (kW)"
                            min="0"
                            step="500"
                            bind:value={pr.conso}
                            on:change={(_ev) =>
                                updatePlot(
                                    puissance,
                                    position,
                                    azimuth,
                                    inclinaison
                                )} />
                        <!-- <input
                             type="number"
                             class="form-control"
                             placeholder="Nombre de compteurs"
                             min="0"
                             step="1"
                             bind:value={pr.nCompteurs}
                             on:change={(_ev) => updatePlot(puissance, position, azimuth, inclinaison)} /> -->
                    </td>
                    <td style="width:1%;white-space:nowrap;text-align:center">
                        <button
                            class="btn btn-link"
                            on:click={(_ev) => delProfil(i)}
                            ><i class="bi bi-x-circle text-primary" /></button>
                    </td>
                </tr>
            {/each}
        </tbody>
    </table>
{/if}
<div class="text-center">
    <button class="btn btn-primary" on:click={addProfil}
        ><i class="bi bi-plus-circle" />&nbsp;Ajouter un profil</button>
</div>

{#if prmsFeature}
    <h2 class="my-5">Relevés de compteurs</h2>
    {#if prms.length}
        <table class="table">
            <thead
                ><tr
                    ><th
                        >PRM<button
                            type="button"
                            class="btn btn-link align-baseline p-0 ms-2"
                            data-bs-toggle="popover"
                            data-bs-trigger="hover focus"
                            data-bs-content="Un PRM, aussi appelé PDL, est l'identifiant d'un compteur électrique. On peut le trouver sur les factures d'électricité, ou en appuyant sur le bouton + du compteur Linky."
                            ><i class="bi bi-question-circle" /></button
                        ></th
                    ><th>Prénom</th><th>Nom</th><th /></tr
                ></thead>
            <tbody>
                {#each prms as prm, i}
                    <tr>
                        <td
                            ><input
                                class="form-control"
                                bind:value={prm.prm}
                                type="number" /></td>
                        <td
                            ><input
                                class="form-control"
                                bind:value={prm.nom} /></td>
                        <td
                            ><input
                                class="form-control"
                                bind:value={prm.prenom} /></td>
                        <td
                            style="width:1%;white-space:nowrap;text-align:center">
                            <button
                                class="btn btn-link"
                                on:click={(ev) => delPrm(ev, i)}
                                ><i
                                    class="bi bi-x-circle text-primary" /></button>
                        </td>
                    </tr>
                {/each}
            </tbody>
        </table>
        <div class="my-3 form-check">
            <input
                class="form-check-input"
                type="checkbox"
                id="consentement"
                bind:checked={consentement} />
            <label class="form-check-label" for="consentement"
                >Ces abonnés consentent à ce que j'accède à leurs données</label>
        </div>
    {/if}
    <div class="d-flex justify-content-center">
        <button class="mx-2 btn btn-primary" on:click={addPrm}
            ><i class="bi bi-plus-circle" />&nbsp;Ajouter un compteur</button>
        {#if prms.length}
            <button
                disabled={!consentement}
                class="mx-2 btn btn-primary"
                form="pdl">Mettre à jour</button>
            <div
                class="mx-2 spinner-border text-primary"
                class:d-none={!prm_loading} />
        {/if}
    </div>
{/if}
<h2 class="mt-5">Simulation</h2>
<table class="table table-bordered d-inline-block">
    <tbody>
        <tr><td>Production totale:</td><td>{Math.round(totalProd)}kWh</td></tr>
        <tr
            ><td>Consommation totale:</td><td>{Math.round(totalConso)}kWh</td
            ></tr>
    </tbody>
</table>
{#if pvgis_loading}
    <div class="my-3 d-flex align-items-center text-primary">
        <div class="spinner-border text-primary me-3" />
        Chargement de la production solaire
    </div>
{/if}

<div class="my-3">
    <div class="mx-auto" style={plotStyle} id="plot" />
</div>
<div class="my-3 row" class:d-none={totalProd == 0 || totalConso == 0}>
    <div class="col-12 col-sm-6 p-0" style={plotStyle} id="autoProd" />
    <div class="col-12 col-sm-6 p-0" style={plotStyle} id="autoConso" />
</div>