import { FastifyInstance } from "fastify"
import { and, eq } from "drizzle-orm"
import { authProfiles, contracts, contracttypes } from "../../../db/schema"
import { insertHistoryItem } from "../../utils/history"

async function getPortalCustomerId(server: FastifyInstance, req: any) {
    const tenantId = req.user?.tenant_id
    const userId = req.user?.user_id

    if (!tenantId || !userId) return null

    const [profile] = await server.db
        .select({ customer_for_portal: authProfiles.customer_for_portal })
        .from(authProfiles)
        .where(and(
            eq(authProfiles.tenant_id, tenantId),
            eq(authProfiles.user_id, userId)
        ))
        .limit(1)

    return profile?.customer_for_portal || null
}

async function getPortalContract(server: FastifyInstance, req: any, contractId: number) {
    const portalCustomerId = await getPortalCustomerId(server, req)
    if (!portalCustomerId) return null

    const [contract] = await server.db
        .select({
            id: contracts.id,
            name: contracts.name,
            tenant: contracts.tenant,
            customer: contracts.customer,
            contracttype: contracts.contracttype,
            allowedContracttypes: contracts.allowedContracttypes,
            archived: contracts.archived,
        })
        .from(contracts)
        .where(and(
            eq(contracts.id, contractId),
            eq(contracts.tenant, req.user?.tenant_id),
            eq(contracts.customer, portalCustomerId),
            eq(contracts.archived, false)
        ))
        .limit(1)

    return contract || null
}

function normalizeMessage(message: unknown) {
    if (typeof message !== "string") return ""
    return message.trim()
}

function appendMessage(text: string, message: string) {
    return message ? `${text} Nachricht: ${message}` : text
}

function formatDateForHistory(value: string) {
    const date = new Date(value)
    if (Number.isNaN(date.getTime())) return value

    return new Intl.DateTimeFormat("de-DE", {
        day: "2-digit",
        month: "2-digit",
        year: "numeric",
        timeZone: "Europe/Berlin",
    }).format(date)
}

export default async function portalContractRoutes(server: FastifyInstance) {
    server.post<{
        Params: { id: string }
        Body: { contracttype?: number | string; message?: string }
    }>("/portal/contracts/:id/change-request", {
        schema: {
            tags: ["Portal"],
            summary: "Request contract type change from customer portal",
            params: {
                type: "object",
                required: ["id"],
                properties: {
                    id: { type: "string" },
                },
            },
            body: {
                type: "object",
                required: ["contracttype"],
                properties: {
                    contracttype: { anyOf: [{ type: "number" }, { type: "string" }] },
                    message: { type: "string", nullable: true },
                },
            },
        },
    }, async (req, reply) => {
        const contractId = Number(req.params.id)
        const requestedContracttypeId = Number(req.body.contracttype)

        if (!Number.isInteger(contractId) || !Number.isInteger(requestedContracttypeId)) {
            return reply.code(400).send({ error: "Ungültige Anfrage" })
        }

        const contract = await getPortalContract(server, req, contractId)
        if (!contract) {
            return reply.code(404).send({ error: "Vertrag nicht gefunden" })
        }

        const [requestedContracttype] = await server.db
            .select({
                id: contracttypes.id,
                name: contracttypes.name,
            })
            .from(contracttypes)
            .where(and(
                eq(contracttypes.id, requestedContracttypeId),
                eq(contracttypes.tenant, req.user?.tenant_id),
                eq(contracttypes.archived, false)
            ))
            .limit(1)

        if (!requestedContracttype) {
            return reply.code(400).send({ error: "Ungültiger Vertragstyp" })
        }

        const allowedContracttypes = Array.isArray(contract.allowedContracttypes)
            ? contract.allowedContracttypes.map((id) => Number(id)).filter((id) => Number.isInteger(id))
            : []

        if (!allowedContracttypes.includes(requestedContracttype.id)) {
            return reply.code(400).send({ error: "Dieser Vertragstyp steht für diesen Vertrag nicht zur Auswahl" })
        }

        const [currentContracttype] = contract.contracttype
            ? await server.db
                .select({
                    id: contracttypes.id,
                    name: contracttypes.name,
                })
                .from(contracttypes)
                .where(and(
                    eq(contracttypes.id, contract.contracttype),
                    eq(contracttypes.tenant, req.user?.tenant_id)
                ))
                .limit(1)
            : []

        const message = normalizeMessage(req.body.message)
        const oldName = currentContracttype?.name || "Ohne Vertragstyp"
        const newName = requestedContracttype.name
        const text = appendMessage(
            `Kundenportal: Änderung des Vertragstyps von "${oldName}" auf "${newName}" angefragt.`,
            message
        )

        await insertHistoryItem(server, {
            tenant_id: req.user?.tenant_id,
            created_by: req.user?.user_id || null,
            entity: "contracts",
            entityId: contract.id,
            action: "unchanged",
            oldVal: { contracttype: contract.contracttype, name: oldName },
            newVal: { contracttype: requestedContracttype.id, name: newName },
            text,
        })

        return { success: true, message: "Ihre Anfrage wurde übermittelt." }
    })

    server.post<{
        Params: { id: string }
        Body: { requestedEndDate?: string; message?: string }
    }>("/portal/contracts/:id/cancellation-request", {
        schema: {
            tags: ["Portal"],
            summary: "Request contract cancellation from customer portal",
            params: {
                type: "object",
                required: ["id"],
                properties: {
                    id: { type: "string" },
                },
            },
            body: {
                type: "object",
                required: ["requestedEndDate"],
                properties: {
                    requestedEndDate: { type: "string" },
                    message: { type: "string", nullable: true },
                },
            },
        },
    }, async (req, reply) => {
        const contractId = Number(req.params.id)
        const requestedEndDate = typeof req.body.requestedEndDate === "string"
            ? req.body.requestedEndDate.trim()
            : ""

        if (!Number.isInteger(contractId) || !requestedEndDate) {
            return reply.code(400).send({ error: "Ungültige Anfrage" })
        }

        const parsedDate = new Date(requestedEndDate)
        if (Number.isNaN(parsedDate.getTime())) {
            return reply.code(400).send({ error: "Ungültiges Kündigungsdatum" })
        }

        const contract = await getPortalContract(server, req, contractId)
        if (!contract) {
            return reply.code(404).send({ error: "Vertrag nicht gefunden" })
        }

        const message = normalizeMessage(req.body.message)
        const text = appendMessage(
            `Kundenportal: Kündigung zum ${formatDateForHistory(requestedEndDate)} angefragt.`,
            message
        )

        await insertHistoryItem(server, {
            tenant_id: req.user?.tenant_id,
            created_by: req.user?.user_id || null,
            entity: "contracts",
            entityId: contract.id,
            action: "unchanged",
            newVal: { requestedEndDate },
            text,
        })

        return { success: true, message: "Ihre Anfrage wurde übermittelt." }
    })
}
