// Identity. Store your memories and mental belongings
// Copyright (C) 2024  SofĂ­a Aritz
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.

import { randomUUID } from "node:crypto";
import list from "./list.js";

import type { AppInterface } from "../../app.js";
import type { AuthInterface } from "../../auth.js";
import { toDBList, type DatabaseInterface } from "../../database.js";
import { Static, Type } from "@sinclair/typebox";

const EntryIDQuery = Type.Object({
    entry_id: Type.String(),
});

type EntryIDQueryType = Static<typeof EntryIDQuery>;

const PutEntryBody = Type.Object({
    entry: Type.Object({
        title: Type.Optional(Type.String()),
        description: Type.Optional(Type.String()),
        creationDate: Type.String(),
        assets: Type.Array(Type.String()),
        feelings: Type.Array(
            Type.Union([
                Type.String(),
                Type.Object({
                    identifier: Type.String(),
                    description: Type.String(),
                    backgroundColor: Type.String(),
                    textColor: Type.String(),
                }),
            ]),
        ),
        base: Type.Union([
            Type.Object({
                kind: Type.String(),
            }),
            Type.Object({
                kind: Type.String(),
                artist: Type.String(),
                title: Type.String(),
                link: Type.Array(Type.String()),
                id: Type.Array(
                    Type.Object({
                        provider: Type.String(),
                        id: Type.String(),
                    }),
                ),
            }),
            Type.Object({
                kind: Type.String(),
                location: Type.Union([
                    Type.String(),
                    Type.Object({
                        latitude: Type.Number(),
                        longitude: Type.Number(),
                    }),
                ]),
            }),
            Type.Object({
                kind: Type.String(),
                referencedDate: Type.String(),
            }),
        ]),
    }),
});

type PutEntryBodyType = Static<typeof PutEntryBody>;

export default function registerRoutes(app: AppInterface, auth: AuthInterface, database: DatabaseInterface) {
    list(app, auth, database);

    app.delete<{ Querystring: EntryIDQueryType }>("/entry", {
        async handler(request) {
            let jwt = request.headers["authorization"].replace("Bearer", "").trim();
            let { payload } = await auth.verifyJwt(jwt);

            let user = await auth.user(payload.uid);
            database.removeEntry(request.query.entry_id);
        },
        schema: {
            headers: { $ref: "schema://identity/authorization" },
            querystring: EntryIDQuery,
        },
    });

    app.put<{ Body: PutEntryBodyType }>("/entry", {
        async handler(request) {
            let jwt = request.headers["authorization"].replace("Bearer", "").trim();
            let { payload } = await auth.verifyJwt(jwt);

            let entry = request.body.entry;

            let musicEntry, locationEntry, dateEntry;
            if ((entry.base.kind === "album" || entry.base.kind === "song") && "artist" in entry.base) {
                musicEntry = {
                    id: randomUUID(),
                    title: entry.base.title,
                    artist: entry.base.artist,
                    links: toDBList(entry.base.link),
                    universalIDs: toDBList(entry.base.id),
                };
            } else if (entry.base.kind === "environment" && "location" in entry.base) {
                locationEntry = {
                    id: randomUUID(),
                    locationText: typeof entry.base.location === "string" ? entry.base.location : undefined,
                    locationCoordinates:
                        typeof entry.base.location === "string" ? undefined : JSON.stringify(entry.base.location),
                };
            } else if (entry.base.kind === "date" && "referencedDate" in entry.base) {
                dateEntry = {
                    id: randomUUID(),
                    referencedDate: Date.parse(entry.base.referencedDate),
                };
            }

            await database.insertEntry(
                {
                    id: randomUUID(),
                    userID: payload.uid,
                    feelings: toDBList(entry.feelings),
                    assets: toDBList(entry.assets),
                    title: entry.title,
                    description: entry.description,
                    kind: entry.base.kind,
                    createdAt: Date.now(),
                },
                musicEntry,
                locationEntry,
                dateEntry,
            );
        },
        schema: {
            headers: { $ref: "schema://identity/authorization" },
            body: PutEntryBody,
        },
    });
}