import jwt from "jsonwebtoken"
import bcrypt from "bcrypt"
import { prisma } from "@/core/prisma"
import { AppError } from "@/core/AppError"
import {generateRefreshToken, hashToken} from "@/utils/auth.utils";
import {User} from "@prisma/client";

const JWT_SECRET = process.env.JWT_SECRET!
const ACCESS_EXPIRES = "1h"

export const adminAuthService = {

    async login(email: string, password: string) {
        const user = await prisma.user.findUnique({ where: { email } })

        if (!user) throw new AppError("Invalid credentials", 401)

        const valid = await bcrypt.compare(password, user.password)
        if (!valid) throw new AppError("Invalid credentials", 401)

        return this.issueTokens(user)
    },

    async issueTokens(user: User) {

        const accessToken = jwt.sign(
            { sub: user.id, type: "admin" },
            JWT_SECRET,
            { expiresIn: "1h" }
        )

        const refreshToken = generateRefreshToken()
        const tokenHash = hashToken(refreshToken)

        await prisma.adminRefreshToken.create({
            data: {
                userId: user.id,
                tokenHash,
                expiresAt: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365)
            }
        })

        return {
            accessToken,
            refreshToken,
            user: {
                id: user.id,
                email: user.email,
                createdAt: user.createdAt.toISOString()
            }
        }
    },

    async refresh(refreshToken: string) {

        const tokenHash = hashToken(refreshToken)

        const stored = await prisma.adminRefreshToken.findUnique({
            where: { tokenHash },
            include: { user: true }
        })

        if (!stored || stored.revoked)
            throw new AppError("Invalid refresh token", 401)

        if (stored.expiresAt < new Date())
            throw new AppError("Refresh expired", 401)

        // Rotation
        await prisma.adminRefreshToken.update({
            where: { id: stored.id },
            data: { revoked: true }
        })

        return this.issueTokens(stored.user)
    },

    async register(email: string, password: string) {
        const existing = await prisma.user.findUnique({ where: { email } })
        if (existing) throw new AppError("Email already used", 400)

        const hashed = await bcrypt.hash(password, 10)

        const user = await prisma.user.create({
            data: {
                email,
                password: hashed
            }
        })
        return this.issueTokens(user)
    }
}

