<script lang="ts">
    import { browser } from '$app/environment'
    import { onMount, tick } from 'svelte'
    import type { Writable } from 'svelte/store'
    import { get } from 'svelte/store'
    import { getContext } from 'svelte'
    import type * as P from 'plotly.js-dist-min'
    import * as Grain from '../../../../../grain-types'
    import {
        chooseScale,
        relayout,
        modeBarButtonsToRemove,
    } from '../../../../../plot'
    import type { Sample } from '../../../../../plot'
    import type { Derived, PVGIS, PVGISInputs } from '../calcul'
    import * as calcul from '../calcul'
    import PlusCircle from '../../../../PlusCircle.svelte'
    import XCircle from '../../../../XCircle.svelte'
    import Question from '../../../../Question.svelte'

    let { data = $bindable(), pvgis_loading = true } = $props()
    const data_ = $state(data)

    let s: Derived = getContext('simulation')
    let prms: Writable<
        {
            prm: null | number
            nom: string
            prenom: string
            siret: string
            pro: boolean
            consentement: boolean
            releve?: string
            numerorue?: string
            codeinsee?: string
            serie?: string
        }[]
    > = getContext('prms')
    let prms_modified: Writable<boolean> = getContext('prms_modified')
    let profils: Writable<{ type: string; conso: number }[]> =
        getContext('profils')
    let profils_modified: Writable<boolean> = getContext('profils_modified')
    const soleil: Writable<Sample> = getContext('soleil')
    const expert: Writable<boolean> = getContext('expert')
    let _communaute: Writable<
        (Grain.Communaute & { isMoving?: boolean }) | null
    > = getContext('communaute')

    const annee = $derived.by(() => {
        console.log('derived by')
        let annee = data.annee
        if (!annee) {
            annee = {}
        }
        for (let i = 0; i < $prms.length; i++) {
            const p = $prms[i]
            if (p.releve) {
                annee[p.prm || i] = []
                for (const j of p.releve.split('\n')) {
                    const l = j.split(/;|,| /)
                    if (l.length >= 2) {
                        const d = new Date(l[0])
                        const v = parseInt(l[1])
                        if (d && !isNaN(v)) {
                            annee[p.prm || i].push(v)
                        }
                    }
                }
                console.log(annee[p.prm || i])
            }
        }
        return annee
    })

    function addPrm() {
        console.log('ajouter un compteur')
        prms.update((prms) => {
            prms.push({
                prm: null,
                nom: '',
                prenom: '',
                siret: '',
                pro: true,
                consentement: false,
            })
            return prms
        })
        prms_modified.set(true)
    }

    const pvgis: Writable<{ pvgis: null | PVGIS; loading: boolean }> =
        getContext('pvgis')
    let pvgis_: null | PVGISInputs = null

    let prm_loading = $state(false)

    let initialised = false

    let puissance = 0
    let communaute: null | (Grain.Communaute & { isMoving?: boolean }) = null

    let Plotly: typeof P

    let erreur = $state('')

    onMount(async () => {
        Plotly = await import('plotly.js-dist-min')
        s.p.puissance.subscribe((value) => {
            puissance = value
            if (initialised) {
                updatePlot(puissance, communaute)
            }
        })
        _communaute.subscribe((value) => {
            communaute = value
            if (initialised) {
                updatePlot(puissance, communaute)
            }
        })
        pvgis.subscribe((pvgis) => {
            console.log('pvgis updated')
            if (initialised && pvgis.pvgis?.inputs != pvgis_) {
                pvgis_ = pvgis.pvgis?.inputs || null
                updatePlot(puissance, communaute)
            }
        })
        if ($prms.length) {
            for (let p of $prms) {
                p.consentement = false
            }
        }
        initialised = true
        updatePlot(puissance, communaute)
    })

    let plotStyle = $state('')

    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_ = $state(Grain.profils($expert))
    expert.subscribe((value) => (profils_ = Grain.profils(value)))

    function addProfil() {
        profils.update((p) => {
            const prt = Object.keys(profils_)
            p.push({ type: prt[0], conso: 0 })
            return p
        })
        profils_modified.set(true)
        updatePlot(puissance, communaute)
    }

    function delProfil(i: number) {
        profils.update((p) => {
            p.splice(i, 1)
            return p
        })
        profils_modified.set(true)
        updatePlot(puissance, communaute)
    }

    const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))

    var lastRequest = performance.now()

    async function refresh(event: SubmitEvent) {
        event.preventDefault()
        prms_modified.set(true)
        if ($prms) {
            prm_loading = true
            await tick()
            for (let i = 0; i < $prms.length; i++) {
                var file = document.getElementById(
                    `releve-${i}`
                ) as HTMLInputElement | null
                console.log('FILE', file?.files)
                if (file?.files?.length) {
                    var reader = new FileReader()
                    reader.readAsText(file.files[0], 'UTF-8')
                    let r: string | undefined = await new Promise((resolve) => {
                        reader.onload = function (evt) {
                            console.log(typeof evt.target?.result)
                            let result = evt.target?.result?.toString()
                            if (result) {
                                resolve(result)
                            } else {
                                resolve(undefined)
                            }
                        }
                    })
                    console.log('r', r)
                    $prms[i].releve = r
                }
                let siret = document.getElementById(
                    `siret-${i}`
                ) as HTMLInputElement | null
                if (siret?.value) {
                    let now = performance.now()
                    // Rate-limiting: pas plus de 7 requêtes par seconde.
                    if (now - lastRequest < 150) {
                        await sleep(150 - (now - lastRequest))
                    }
                    lastRequest = now
                    const resp = await fetch(
                        `https://recherche-entreprises.api.gouv.fr/search?q=${siret.value}`
                    )
                    if (resp.status == 200) {
                        type Ent = {
                            results: {
                                dirigeants: {
                                    nom: string
                                    prenoms: string
                                }[]
                                matching_etablissements: {
                                    libelle_voie: string
                                    commune: string
                                }[]
                            }[]
                        }
                        let ent: Ent = await resp.json()
                        console.log(
                            ent.results[0].matching_etablissements[0].commune
                        )
                        if (ent.results.length) {
                            $prms[i].nom = ent.results[0].dirigeants[0].nom
                            $prms[i].prenom =
                                ent.results[0].dirigeants[0].prenoms
                            $prms[i].codeinsee =
                                ent.results[0].matching_etablissements[0].commune
                            console.log($prms[i])
                        }
                    }
                }
            }
            console.log($prms)
            const resp = await fetch(
                `${Grain.server}/api/grain/projet/${data_.id || 'nouveau'}/prms`,
                {
                    method: 'POST',
                    body: JSON.stringify($prms),
                }
            )
            if (resp.ok) {
                data.annee = await resp.json()
            }
            prm_loading = false
            await tick()
        } else {
            erreur = 'La liste des PRMs est vide'
        }
        await updatePlot(puissance, communaute)
    }

    let auto = 0
    let totalProd = $state(0)
    let totalConso = $state(0)

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

    async function updatePv(
        puissance: number,
        communaute: (Grain.Communaute & { isMoving?: boolean }) | null
    ) {
        if (communaute?.isMoving) {
            return pvgis
        }
        pvgis_loading = true
        await calcul.updatePv(puissance, communaute, pvgis, soleil)
        pvgis_loading = false
        await tick()
    }

    async function updatePlot(
        puissance: number,
        communaute: (Grain.Communaute & { isMoving?: boolean }) | null
    ) {
        console.log('isMoving', communaute?.isMoving)
        if (communaute?.isMoving) {
            return
        }
        if (!browser) {
            return
        }

        await updatePv(puissance, communaute)
        console.log('updated')
        prm_loading = true
        let auto_ = await calcul.updatePlot(
            annee || {},
            $profils,
            profils_,
            somme,
            soleil
        )
        prm_loading = false
        auto = auto_.auto
        totalProd = auto_.totalProd
        totalConso = auto_.totalConso
        console.log('updated auto', auto, totalProd, totalConso)
        if (!Plotly) {
            Plotly = await import('plotly.js-dist-min')
        }
        redraw()
    }

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

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

    function redraw() {
        console.log('redraw')
        const plot = document.getElementById('plot')
        if (!plot) return
        let soleil_ = get(soleil)
        chooseScale(plot, soleil_)
        chooseScale(plot, 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,
                tickformat: soleil_.bucket < 24 ? '%x %X' : '%x',
                type: 'datetime',
            },
            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',
            },
        }

        if (has_plot.has_plot) {
            console.log('has plot')
            //@ts-expect-error Plotly+typescript = meh
            Plotly!.update(plot, [soleil, somme], layout)
        } else {
            console.log("doesn't have plot")
            //@ts-expect-error Plotly+typescript = meh
            Plotly!.newPlot(plot, [soleil_, somme], layout, {
                responsive: true,
                modeBarButtonsToRemove: modeBarButtonsToRemove,
            })
            //@ts-expect-error Plotly+typescript = meh
            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,
            },
        ]

        if (totalProd && totalConso) {
            plotStyle = 'min-height:450px'
            Plotly.react(
                'autoProd',
                //@ts-expect-error Plotly+typescript = meh
                dataProd,
                {
                    title: "Autoconsommation sur l'année",
                    font: {
                        color: darkMode ? '#fff' : '#000',
                    },
                    plot_bgcolor: '#fff0',
                    paper_bgcolor: '#fff0',
                    autosize: true,
                    automargin: true,
                    legend: {
                        orientation: 'h',
                    },
                },
                { responsive: true }
            )
            Plotly.react(
                'autoConso',
                //@ts-expect-error Plotly+typescript = meh
                dataConso,
                {
                    title: "Autoproduction sur l'année",
                    font: {
                        color: darkMode ? '#fff' : '#000',
                    },
                    plot_bgcolor: '#fff0',
                    paper_bgcolor: '#fff0',
                    autosize: true,
                    automargin: true,
                    legend: {
                        orientation: 'h',
                    },
                },
                { responsive: true }
            )
        } else {
            plotStyle = ''
        }
    }
</script>

<div class="p-10 flex flex-col">
    <h1 class="my-8 text-4xl font-bold">
        Production… <span class="text-primary">Consommation</span>
    </h1>

    <form
        class="mt-10"
        method="POST"
        action="/api/grain"
        id="pdl"
        onsubmit={refresh}>
    </form>
    {#if erreur}
        <div
            id="erreur"
            class="alert alert-error fade flex"
            class:show={erreur}
            role="alert">
            <div>
                {erreur}
            </div>
            <button
                type="button"
                class="ms-auto"
                onclick={() => (erreur = '')}
                aria-label="Close">
                <svg
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke-width="1.5"
                    stroke="currentColor"
                    class="w-5">
                    <path
                        stroke-linecap="round"
                        stroke-linejoin="round"
                        d="M6 18 18 6M6 6l12 12" />
                </svg>
            </button>
        </div>
    {/if}
    <h2 class="text-2xl my-5">Profils de consommation</h2>
    {#if $profils?.length}
        {#if $expert}
            <div>
                Vous êtes en mode expert. Dans ce mode, vous avez un accès
                direct à tous les profils utilisés par les opérateurs du réseau
                pour simuler les consommations. Voir <a
                    href="https://www.enedis.fr/responsable-dequilibre-profilage-et-profils"
                    >la documentation</a
                >.
            </div>
        {/if}
        <table class="table w-auto mx-auto my-5">
            <thead
                ><tr
                    ><th>Profil</th><th>Consommation annuelle (kWh)</th><th></th
                    ></tr
                ></thead>
            <tbody>
                {#each $profils as pr, i (i)}
                    <tr>
                        <td>
                            <select
                                class="select"
                                bind:value={pr.type}
                                onchange={() => {
                                    profils_modified.set(true)
                                    updatePlot(puissance, communaute)
                                }}>
                                {#each Object.keys(profils_) as p (p)}
                                    <option value={p}>{p}</option>
                                {/each}
                            </select>
                        </td>
                        <td>
                            <input
                                type="number"
                                class="input"
                                placeholder="Abonnement (kW)"
                                min="0"
                                step="500"
                                bind:value={pr.conso}
                                onchange={() =>
                                    updatePlot(puissance, communaute)} />
                        </td>
                        <td>
                            <button
                                class="text-primary"
                                onclick={() => delProfil(i)}
                                aria-label="Supprimer ce profil"
                                ><XCircle /></button>
                        </td>
                    </tr>
                {/each}
            </tbody>
        </table>
    {/if}
    <button class="mx-auto btn btn-primary" onclick={addProfil}
        ><PlusCircle />&nbsp;Ajouter un profil</button>

    <h2 class="text-2xl mt-10 my-5">Relevés de compteurs</h2>
    {#if data_.active && data_.id && data_.id != 'nouveau'}
        <div class="mb-5">
            Vous pouvez ajouter des compteurs d'entreprises ou d'associations
            par leur numéro de compteur et leur numéro de SIRET.
        </div>
        {#if $prms?.length}
            {#each $prms as prm, i (prm)}
                <div class="flex flex-wrap gap-x-10 gap-5">
                    <div class="flex flex-col w-full gap-2">
                        <div class="flex">
                            <label class="label" for="prm-{i}">PRM</label
                            >&nbsp;<Question
                                datatip="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." />
                        </div>
                        <div class="flex gap-1">
                            <input
                                class="input input-sm"
                                id="prm-{i}"
                                bind:value={prm.prm}
                                onkeydown={(e) =>
                                    (e.key == 'ArrowUp' ||
                                        e.key == 'ArrowDown') &&
                                    e.preventDefault()}
                                type="number" />
                            <button
                                class="btn btn-outline btn-primary btn-sm ms-auto"
                                onclick={(e) => {
                                    e.preventDefault()
                                    $prms.splice(i, 1)
                                }}
                                aria-label="Supprimer ce compteur"
                                ><XCircle /></button>
                        </div>
                    </div>
                    <div class="flex flex-col gap-2">
                        <label class="label" for="prm-{i}"
                            >Relevé au format CSV</label>
                        <div class="flex">
                            <input
                                class="file-input file-input-sm"
                                id="releve-{i}"
                                type="file" />
                            {#if prm.releve?.length}
                                <Question
                                    datatip="Nous avons enregistré votre fichier, mais vous pouvez le mettre à jour à tout moment." />
                            {/if}
                        </div>
                    </div>
                    <div class="flex gap-5">
                        <div class="flex gap-2 items-center">
                            <input
                                type="radio"
                                class="radio radio-sm"
                                id="particulier"
                                value={false}
                                bind:group={prm.pro} />
                            <label class="label" for="particulier"
                                >Particulier</label>
                        </div>
                        <div class="flex gap-2 items-center">
                            <input
                                type="radio"
                                class="radio radio-sm"
                                id="pro"
                                value={true}
                                bind:group={prm.pro} />
                            <label class="label" for="pro">Professionnel</label>
                        </div>
                    </div>
                    {#if prm.pro}
                        <div class="flex flex-col my-2 gap-2 w-full">
                            <label class="label" for="siret-{i}"
                                >SIRET du titulaire du compteur</label>
                            <input
                                class="input input-sm"
                                id="siret-{i}"
                                bind:value={prm.siret} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="prenom-{i}"
                                >Prénom du titulaire du compteur</label>
                            <input
                                class="input input-sm"
                                id="prenom-{i}"
                                bind:value={prm.prenom} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="nom-{i}"
                                >Nom du titulaire du compteur</label>
                            <input
                                class="input input-sm"
                                id="nom-{i}"
                                bind:value={prm.nom} />
                        </div>
                    {:else}
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="prenom-{i}"
                                >Prénom du titulaire du compteur</label>
                            <input
                                class="input input-sm"
                                id="prenom-{i}"
                                bind:value={prm.prenom} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="nom-{i}"
                                >Nom du titulaire du compteur</label>
                            <input
                                class="input input-sm"
                                id="nom-{i}"
                                bind:value={prm.nom} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="numerorue-{i}"
                                >Numéro et rue</label>
                            <input
                                class="input input-sm"
                                id="numerorue-{i}"
                                bind:value={prm.numerorue} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="codepostal-{i}"
                                >Code INSEE de la commune</label>

                            <input
                                class="input input-sm"
                                id="codepostal-{i}"
                                bind:value={prm.codeinsee} />
                        </div>
                        <div class="flex flex-col my-2 gap-2">
                            <label class="label" for="serie-{i}"
                                >Numéro de série</label>
                            <input
                                class="input input-sm"
                                id="serie-{i}"
                                bind:value={prm.serie} />
                        </div>
                    {/if}
                    <div class="flex items-center gap-2">
                        <input
                            class="checkbox checkbox-primary checkbox-sm"
                            type="checkbox"
                            id="consentement-{i}"
                            bind:checked={prm.consentement} />
                        <label class="label" for="consentement-{i}"
                            >Cet abonné consent à ce que j'accède à ses données.</label>
                    </div>
                    <hr class="my-4" />
                </div>
            {/each}
            <div class="my-3">
                Ce service ne consulte la courbe de charge du compteur
                communiquant qu'une seule fois, et ce consentement expire dès
                que ces données pour l'année écoulée sont récupérées. Les
                données collectées depuis les compteurs communiquants sont
                stockées temporairement sur nos serveurs pour des raisons de
                performance, ne sont utilisées que pour afficher cette page et
                produire le rapport, et ne sont jamais conservées plus de 30
                jours.
            </div>
            <div class="my-3">
                Les données envoyées via un fichier sont conservées jusqu'à ce
                que vous supprimiez ce projet.
            </div>
        {/if}
        <div class="flex justify-center my-10">
            <button class="mx-2 btn btn-primary" onclick={addPrm}
                ><PlusCircle />&nbsp;Ajouter un compteur</button>
            {#if $prms.length}
                <button class="mx-2 btn btn-primary" form="pdl"
                    >Mettre à jour</button>
                <div
                    class="mx-2 loading text-primary"
                    class:hidden={!prm_loading}>
                </div>
            {/if}
        </div>
    {:else if data_.active}
        <div class="my-3">
            Sauvegardez ce projet pour avoir accès aux relevés de compteurs
            détaillés.
        </div>
    {:else}
        <div class="my-3">
            Vous devez être abonné pour avoir accès aux relevés de compteurs
            détaillés. Cependant, si vous disposez des relevés au format CSV (au
            format de ligne: <code>2025-11-18T14:00:00+01:00; 440</code>),
            n'hésitez pas à les fournir ici.
        </div>
    {/if}
    {#if $prms?.length}
        {#each $prms as prm, i (prm)}
            <div class="flex flex-col my-2 gap-2">
                <label class="label" for="prm-{i}">Relevé au format CSV</label>
                <div class="flex items-center gap-2">
                    <input
                        class="file-input file-input-sm"
                        id="releve-{i}"
                        type="file" />
                    {#if prm.releve?.length}
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            fill="none"
                            viewBox="0 0 24 24"
                            stroke-width="1.5"
                            stroke="currentColor"
                            class="size-6">
                            <path
                                stroke-linecap="round"
                                stroke-linejoin="round"
                                d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
                        </svg>
                    {/if}
                    <button
                        class="btn btn-outline btn-primary btn-sm"
                        onclick={(e) => {
                            e.preventDefault()
                            $prms.splice(i, 1)
                        }}
                        aria-label="Supprimer ce compteur"><XCircle /></button>
                </div>
            </div>
        {/each}
    {/if}
    <div class="flex justify-center my-5">
        <button class="mx-2 btn btn-primary" onclick={addPrm}
            ><PlusCircle />&nbsp;Ajouter un compteur</button>
        {#if $prms.length}
            <button class="mx-2 btn btn-primary" form="pdl"
                >Mettre à jour</button>
            <div class="mx-2 loading text-primary" class:hidden={!prm_loading}>
            </div>
        {/if}
    </div>
    <h2 class="text-2xl mt-5 my-10">Simulation</h2>
    <div class="me-auto">
        <table class="table inline-block">
            <tbody>
                <tr
                    ><td>Production totale:</td><td
                        >{#if isNaN(totalProd)}Calcul: impossible{:else}{Math.round(
                                totalProd
                            )}kWh{/if}</td
                    ></tr>
                <tr
                    ><td>Consommation totale:</td><td
                        >{Math.round(totalConso)}kWh</td
                    ></tr>
            </tbody>
        </table>
    </div>
    {#if pvgis_loading}
        <div class="flex items-center text-primary my-5 gap-3">
            <div class="loading text-primary"></div>
            Chargement de la production solaire
        </div>
    {/if}

    <div class="my-3">
        <div class="mx-auto" style="min-height:450px" id="plot"></div>
    </div>
    <div class="flex flex-wrap">
        <div class="p-0 m-0 sm:w-1/2 w-full" style={plotStyle} id="autoProd">
        </div>
        <div class="p-0 m-0 sm:w-1/2 w-full" style={plotStyle} id="autoConso">
        </div>
    </div>
</div>

<style>
    input::-webkit-outer-spin-button,
    input::-webkit-inner-spin-button {
        -webkit-appearance: none;
        margin: 0;
    }
    input[type='number'] {
        appearance: none;
        -moz-appearance: textfield; /* Firefox */
    }
</style>
