/**
 *
 * @description This endpoint handle the auth
 * * source : https://nextjs.org/docs/app/building-your-application/routing/route-handlers
 * *          https://nextjs.org/docs/app/api-reference/functions/cookies
 */

import dbConnect from '@/database/dbConnect'
import { IAuthReqBody , IAuthResData } from '@/types/IAPI'
import { IUserSchema } from '@/types/IDB'
import { NextResponse } from 'next/server'
import bcrypt from 'bcrypt'
import userModel from '@/database/models/userModel'
import { cookies } from 'next/headers'
import crypto from "crypto"

// handle the signin process by creating and sending the authToken
export async function POST(req : Request)
{
    try {
        // connect to the db
        dbConnect(); 
        // get the request body
        const reqBody : IAuthReqBody = await req.json()
        let responseData : IAuthResData;
        // see if valid username
        let userDoc : IUserSchema | null = await userModel.findOne({ username : reqBody.username })

        // if invalid username
        if(!userDoc)
        {
            responseData = {
                success: false,
                message: "invalidUsername",
            }
            
            return NextResponse.json(responseData , {
                status: 200,
                headers: { "content-type": "application/json" }
            })
        }
        // there is a user with that username
        else
        {
            let passwordCheckResult = await bcrypt.compare(reqBody.password, userDoc.password)
            // the password is wrong
            if(!passwordCheckResult)
            {
                responseData = {
                    success: false,
                    message: "wrongPassword",
                }
                
                return NextResponse.json(responseData , {
                    status: 200,
                    headers: { "content-type": "application/json" }
                })
            }
            else
            // password matched so logging successfully
            {
                let authToken = crypto.randomBytes(32).toString('hex');
                // save the token to the db
                await userModel.findOneAndUpdate({username: reqBody.username} , {
                    $set: {
                        "token" : {
                            value: authToken,
                            expiresAt: Math.floor(Date.now() / 1000) + 3 * 60 * 60,
                        }
                    }
                })

                // set the authToken cookie
                cookies().set('authToken', authToken, { secure: true })
                // prepare the response
                responseData = {
                    success: true,
                    message: "loggedIn",
                    authToken: authToken,
                }
                // & sent the response with success set to true
                return NextResponse.json(responseData , {
                    status: 200,
                    headers: { "content-type": "application/json" }
                })
            }
        }
    // there was an error while handling this request
    }catch(e) { 
        return NextResponse.json({
            success: false,
            message: "serverError",
        } , {
            status: 500,
            headers: { "content-type": "application/json" }
        })
    }
}

// revalidate every 10 seconds
export const revalidate = 10;

// handle the check authToken validation
export async function GET(req: Request)
{
    try {
        // connect to the database first
        await dbConnect();
        
        // get the request params
        const { searchParams } = new URL(req.url)
        const authToken = searchParams.get('authToken')

        // trow error if invalid auth token
        if(!authToken)
        {
            throw {
                specialError : 'invalidRequest'
            }
        }
        else if(authToken == 'null')
        {
            throw {
                specialError : 'invalidRequest'
            }
        }
        // if there was a valid authToken cookie
        else
        {
            // we try to get the user by the authToken
            let userDoc = await userModel.findOne({'token.value': authToken})
            // if the authToken is invalid we go return
            if(!userDoc)
            {
                throw {
                    specialError : 'invalidToken'
                }
            }
            // if the authToken if valid we check if it expired or not yet
            // we throw error if expired
            if(userDoc.token.expiresAt < (Date.now() / 1000))
            {
                throw {
                    specialError : 'expiredToken'
                }
            }
            // we return true
            else
            {
                return NextResponse.json({
                    success: true,
                    message: "userIsLoggedIn",
                } , {
                    status: 200,
                })
            }
        }
    // there was an error while handling this request
    }catch(e : any) {
        if(e.specialError) {
            return NextResponse.json({
                success: false,
                message: e.specialError,
            } , {
                status: 200,
            })
        }
        else
        {
            return NextResponse.json({
                success: false,
                message: "serverError",
            } , {
                status: 500,
            })
        }
    }
}