import { FastifyInstance } from "fastify";
import bcrypt from "bcrypt";
import { generateRandomPassword, hashPassword } from "../../utils/password";
import { sendMail } from "../../utils/mailer";

import { authUsers } from "../../../db/schema";
import { authTenantUsers } from "../../../db/schema";
import { tenants } from "../../../db/schema";
import { eq } from "drizzle-orm";
import {
    createAccessToken,
    issueRefreshToken,
    revokeRefreshToken,
    rotateRefreshToken,
} from "../../utils/authTokens";

export default async function authRoutes(server: FastifyInstance) {

    // -----------------------------------------------------
    // REGISTER
    // -----------------------------------------------------
    server.post("/auth/register", {
        schema: {
            tags: ["Auth"],
            summary: "Register User",
            body: {
                type: "object",
                required: ["email", "password"],
                properties: {
                    email: { type: "string", format: "email" },
                    password: { type: "string" },
                },
            },
        },
    }, async (req, reply) => {
        const body = req.body as { email: string; password: string };

        const passwordHash = await bcrypt.hash(body.password, 10);

        const [user] = await server.db
            .insert(authUsers)
            .values({
                email: body.email.toLowerCase(),
                passwordHash,
            })
            .returning({
                id: authUsers.id,
                email: authUsers.email,
            });

        return { user };
    });


    // -----------------------------------------------------
    // LOGIN
    // -----------------------------------------------------
    server.post("/auth/login", {
        schema: {
            tags: ["Auth"],
            summary: "Login User",
            body: {
                type: "object",
                required: ["email", "password"],
                properties: {
                    email: { type: "string", format: "email" },
                    password: { type: "string" },
                    rememberMe: { type: "boolean" },
                },
            },
        },
    }, async (req, reply) => {
        const body = req.body as { email: string; password: string; rememberMe?: boolean };

        let user: any = null;

        // -------------------------------
        // SINGLE TENANT MODE
        // -------------------------------
       /* if (req.tenant) {
            const tenantId = req.tenant.id;

            const result = await server.db
                .select({
                    user: authUsers,
                })
                .from(authUsers)
                .innerJoin(
                    authTenantUsers,
                    eq(authTenantUsers.userId, authUsers.id)
                )
                .innerJoin(
                    tenants,
                    eq(authTenantUsers.tenantId, tenants.id)
                )
                .where(and(
                    eq(authUsers.email, body.email.toLowerCase()),
                    eq(authTenantUsers.tenantId, tenantId)
                ));

            if (result.length === 0) {
                return reply.code(401).send({ error: "Invalid credentials" });
            }

            user = result[0].user;

            // -------------------------------
            // MULTI TENANT MODE
            // -------------------------------
        } else {*/
            const [found] = await server.db
                .select()
                .from(authUsers)
                .where(eq(authUsers.email, body.email.toLowerCase()))
                .limit(1);

            if (!found) {
                return reply.code(401).send({ error: "Invalid credentials" });
            }

            user = found;
        /*}*/

        // Passwort prüfen
        const valid = await bcrypt.compare(body.password, user.passwordHash);
        if (!valid) {
            return reply.code(401).send({ error: "Invalid credentials" });
        }

        const tenantId = req.tenant?.id ? Number(req.tenant.id) : null;
        const token = createAccessToken(user, tenantId);
        const refreshToken = await issueRefreshToken(server, user.id, tenantId);

        reply.setCookie("token", token, {
            path: "/",
            httpOnly: true,
            sameSite: process.env.NODE_ENV === "production" ? "none" : "lax",
            secure: process.env.NODE_ENV === "production",
            ...(body.rememberMe ? { maxAge: 60 * 60 * 6 } : {}),
        });

        return { token, refreshToken };
    });

    server.post("/auth/refresh", {
        schema: {
            tags: ["Auth"],
            summary: "Refresh a persistent session",
            body: {
                type: "object",
                required: ["refreshToken"],
                properties: {
                    refreshToken: { type: "string" },
                },
            },
        },
    }, async (req, reply) => {
        const { refreshToken } = req.body as { refreshToken: string };
        const refreshed = await rotateRefreshToken(server, refreshToken);

        if (!refreshed) {
            return reply.code(401).send({ error: "Invalid or expired refresh token" });
        }

        return refreshed;
    });

    // -----------------------------------------------------
    // LOGOUT
    // -----------------------------------------------------
    server.post("/auth/logout", {
        schema: {
            tags: ["Auth"],
            summary: "Logout User"
        }
    }, async (req, reply) => {
        const refreshToken = (req.body as { refreshToken?: string } | undefined)?.refreshToken;
        if (refreshToken) {
            await revokeRefreshToken(server, refreshToken);
        }
        reply.clearCookie("token", {
            path: "/",
            httpOnly: true,
            secure: process.env.NODE_ENV === "production",
            sameSite: "lax",
        });

        return { success: true };
    });


    // -----------------------------------------------------
    // PASSWORD RESET
    // -----------------------------------------------------
    server.post("/auth/password/reset", {
        schema: {
            tags: ["Auth"],
            summary: "Reset Password",
            body: {
                type: "object",
                required: ["email"],
                properties: {
                    email: { type: "string", format: "email" }
                }
            }
        }
    }, async (req, reply) => {
        const { email } = req.body as { email: string };

        const [user] = await server.db
            .select({
                id: authUsers.id,
                email: authUsers.email,
            })
            .from(authUsers)
            .where(eq(authUsers.email, email.toLowerCase()))
            .limit(1);

        if (!user) {
            return reply.code(404).send({ error: "User not found" });
        }

        const plainPassword = generateRandomPassword();
        const passwordHash = await hashPassword(plainPassword);


        await server.db
            .update(authUsers)
            .set({
                passwordHash,
                // @ts-ignore
                mustChangePassword: true,
            })
            .where(eq(authUsers.id, user.id));

        await sendMail(
            user.email,
            "FEDEO | Dein neues Passwort",
            `
        <p>Hallo,</p>
        <p>Dein Passwort wurde zurückgesetzt.</p>
        <p><strong>Neues Passwort:</strong> ${plainPassword}</p>
        <p>Bitte ändere es nach dem Login umgehend.</p>
      `
        );

        return { success: true };
    });
}
