import type { Grain } from './helpers'

interface Env {}

export default {}

export class User {
    env: Env
    state: DurableObjectState

    constructor(state: DurableObjectState, env: Env) {
        this.state = state
        this.env = env
    }

    async fetch(request: Request): Promise<Response> {
        console.log('parsing json')
        let json = <Grain.Cmd>await request.json()
        console.log(`parsed ${JSON.stringify(json)}`)
        return await this.fetchCmd(json)
    }

    async fetchCmd(json: Grain.Cmd): Promise<Response> {
        let headers = new Headers()
        headers.set('Content-Type', 'application/json')
        // Grain
        if ('ListProjets' in json) {
            return new Response(JSON.stringify(await this.listprojets()), {
                headers,
            })
        }

        if ('CreateProjet' in json) {
            let id = crypto.randomUUID()
            await this.state.storage.put(`pi.${id}`, {
                nom: json.CreateProjet.nom,
                porteur: json.CreateProjet.porteur,
                tel: json.CreateProjet.tel,
                adresse: json.CreateProjet.adresse,
                simulation: json.CreateProjet.simulation,
                t: Date.now(),
            })
            console.log('saved', id)
            return new Response(JSON.stringify(id), { headers })
        }

        if ('SaveProjet' in json) {
            let x: undefined | Grain.GetProjetResp =
                await this.state.storage.get(`pi.${json.SaveProjet.id}`)
            if (x) {
                x.nom = json.SaveProjet.nom || x.nom
                x.porteur = json.SaveProjet.porteur || x.porteur
                x.tel = json.SaveProjet.tel || x.tel
                x.adresse = json.SaveProjet.adresse || x.adresse
                x.simulation = json.SaveProjet.simulation || x.simulation
                await this.state.storage.put(`pi.${json.SaveProjet.id}`, x)
            } else {
                console.log('no such project')
            }
            return new Response('null', { headers })
        }

        if ('GetProjet' in json) {
            let resp = <Grain.GetProjetResp>(
                await this.state.storage.get(`pi.${json.GetProjet}`)
            )
            console.log('resp', JSON.stringify(resp))
            if (resp) {
                resp.id = json.GetProjet
            }
            return new Response(JSON.stringify(resp || null), { headers })
        }

        if ('DelProjet' in json) {
            let t: undefined | { t: string } = await this.state.storage.get(
                `pi.${json.DelProjet.id}`
            )
            if (t) {
                await this.state.storage.delete(`pi.${json.DelProjet.id}`)
            }
            return new Response('null', { headers })
        }

        const exhaustiveCheck: never = json
        throw new Error(exhaustiveCheck)
    }

    async listprojets(_from?: number): Promise<Grain.ListProjetsResp> {
        let opts = {
            prefix: 'pi.',
        }
        let keys: Map<
            string,
            {
                id: string
                nom: string
                simulation: Grain.SimulationCommunaute
                t: number
            }
        > = await this.state.storage.list(opts)
        let result: Grain.ListProjetsResp = []
        for (let [k, v] of keys.entries()) {
            console.log(k, v)
            if (!v.nom) {
                await this.state.storage.delete(k)
                continue
            }
            result.push({
                id: k.slice(3),
                nom: v.nom,
                puissance: v.simulation.puissance,
                t: v.t,
            })
        }
        return result
    }
}