import dbConnect from "@/database/dbConnect";
import { NextResponse } from "next/server";
import memberModel from "@/database/models/memberModel";
import serviceModel from "@/database/models/serviceModel";
import mongoose from 'mongoose'
import statisticsModel from "@/database/models/statisticsModel";
import incomeModel from "@/database/models/incomeModel";

// POST METHOD
export async function POST(req:Request)
{
    try{
        // connect to the db
        dbConnect();
        // get the request payload
        const { payload } = await req.json();
        // declare the needed variables
        const firstName : string | null = payload.firstName as string | null,
        lastName : string | null = payload.lastName as string | null,
        email : string | null = payload.email as string | null,
        phone : string | null = payload.phone as string | null,
        address : string | null = payload.address as string | null,
        services : [string] | [] = payload.services as [string] | [],
        planDelay : number = payload.planDelay ? payload.planDelay : 1 as number,
        gendre : string | null = payload.gendre as string | null,
        bodyState : {
            startBodyForm: String,
            startWeight: Number,
        } | null = payload.bodyState as {
            startBodyForm: String,
            startWeight: Number,
        } | null;
        // calculat month pay
        const ids = services?.map((v , i) => {
            return new mongoose.Types.ObjectId(v as any)
        })
        const servicesDocs = await serviceModel.aggregate([
            {
                $match: {
                    _id: { $in : ids }
                }
            },
            {
                $group: {
                    _id: null,
                    totalPrice: {
                        $sum: "$price"
                    }
                }
            }
        ])
        // inc the value of totalSubscribers for all included services in the membership
        await serviceModel.updateMany({_id : {$in : ids}} , {
            $inc: {
                totalSubscribers: 1
            }
        })
        const payMonth : number = servicesDocs[0] ? servicesDocs[0].totalPrice : 0
        // declare needed variables
        let current_date = new Date(),
        current_date_unix = Math.floor(Date.now() / 1000),
        planDelay_unix = planDelay ? planDelay * 2592000: 0 * 2592000,
        planExpAt = new Date((current_date_unix + planDelay_unix) * 1000);
        // save the doc
        const doc = new memberModel({
            firstName,
            lastName,
            email,
            phone,
            address,
            payMonth,
            services,
            gendre,
            bodyState,
            registerAt: current_date.toUTCString(),
            registerAt_unix: current_date_unix,
            planUpdatedAt: current_date.toUTCString(),
            planUpdatedAt_unix: current_date_unix,
            planDelay,
            planDelay_unix: planDelay_unix,    
            planExpAt: planExpAt.toUTCString(),
            planExpAt_unix: current_date_unix + planDelay_unix,
            active: true,
        })
        await doc.save()

        // return the success response with the new added doc
        return NextResponse.json({
            success: true,
            message: "requestTerminatedWithSuccess",
            data: doc,
        }, {
            status: 200,
            headers: {
                "content-type": "application/json"
            }
        })
    }catch(e)
    {
        // catch any error and return an error response
        return NextResponse.json({
            success: false,
            message: "serverError",
        }, {
            status: 500,
            headers: {
                "content-type": "application/json"
            }
        })
    }
}
// set the revalidate variable
export const revalidate = 5;
// GET METHOD
export async function GET(req:Request)
{
    try{
        // connect to the db
        dbConnect();
        // get the parms
        const { searchParams } = new URL(req.url)
        const type = searchParams.get('type')
        // if get by page
        if(type=='page')
        {
            // get the page
            const page : string | null = searchParams.get('page') ? searchParams.get('page') : '0',
            range : number[] = [(parseInt(page?page : '0') - 1) * 4 , 4];
            // get the docs
            const docs = await memberModel.find({}).skip(range[0]).limit(range[1]),
            // get the size of the docs
            docs_count = await memberModel.countDocuments({});
            // prepare the return data
            return NextResponse.json({
                success: true,
                message: "docsGetedSuccessfully",
                data: {
                    docs,
                    docs_count,
                }
            })
        }
        // if type is search
        else if(type == 'search')
        {
            // get the searchKeyword param
            let searchKeyword = searchParams.get('searchKeyword')
            // get the search results docs
            let results = await memberModel.find({
                $or: [
                    // search by ( case insensitive search )
                    { firstName: { $regex: searchKeyword, $options: 'i' } },
                    { lastName: { $regex: searchKeyword, $options: 'i' } },
                    { email: { $regex: searchKeyword, $options: 'i' } },
                    { phone: { $regex: searchKeyword, $options: 'i' } },
                ]
            })
            // get the docs
            let responseData = {
                docs: results,
                docs_count : results.length,
            }
            // return the response
            return NextResponse.json({
                success: true,
                message: "docsGetedSuccessfully",
                data: responseData ? responseData : [],
            } , {
                status: 200,
            })
        }
    }catch(e)
    {
        // catch any error and return an error response
        return NextResponse.json({
            success: false,
            message: "serverError",
        }, {
            status: 500,
            headers: {
                "content-type": "application/json"
            }
        })
    }
}
// DELETE METHOD
export async function DELETE(req:Request)
{
    try{
        // connect to the db
        dbConnect();
        // get the parms
        const { searchParams } = new URL(req.url)
        const page = searchParams.get('page'),        
        _id : string | null = searchParams.get('_id'),
        range : number[] = [(parseInt(page?page : '0') - 1) * 4 , 4];
        // delete the doc
        await memberModel.findByIdAndRemove(_id)
        // get the docs by page
        const docs = await memberModel.find({}).skip(range[0]).limit(range[1]),
        // get the size of the docs
        docs_count = await memberModel.countDocuments({});
        // prepare the return data
        return NextResponse.json({
            success: true,
            message: "docsGetedSuccessfully",
            data: {
                docs,
                docs_count,
            }
        })
    }catch(e)
    {
        // catch any error and return an error response
        return NextResponse.json({
            success: false,
            message: "serverError",
        }, {
            status: 500,
            headers: {
                "content-type": "application/json"
            }
        })
    }
}
// PUT METHOD
export async function PUT(req:Request)
{
    try{
        // connect to the db
        dbConnect();
        // get the request payload
        const { args , payload } = await req.json();
        // check the type
        const type : "personal" | "subscription" | null = args.type as "personal" | "subscription" | null;
        if(type == "personal")
        {
            // declare the needed variables
            const _id : string | null = payload._id as string | null,
            firstName : string | null = payload.firstName as string | null,
            lastName : string | null = payload.lastName as string | null,
            email : string | null = payload.email as string | null,
            phone : string | null = payload.phone as string | null,
            address : string | null = payload.address as string | null,
            active : boolean | null = payload.active as boolean | null;
            // save the doc
            const doc = await memberModel.findByIdAndUpdate( _id , {
                firstName,
                lastName,
                email,
                phone,
                address,
                active,
            } , {
                new: true
            })
            // return the success response
            return NextResponse.json({
                success: true,
                message: "requestTerminatedWithSuccess",
                data: doc,
            }, {
                status: 200,
                headers: {
                    "content-type": "application/json"
                }
            })
        }       
        else if(type == "subscription")
        {
            // declare the needed variables
            const _id : string | null = payload._id as string | null,
            services : [string] | [] = payload.services as [string] | [],
            planDelay : number = payload.planDelay ? payload.planDelay : 1 as number,
            bodyState : {
                currentBodyForm: String,
                currentWeight: Number,
            } | null = payload.bodyState as {
                currentBodyForm: String,
                currentWeight: Number,
            } | null;
            // calculat month pay
            const ids = services?.map((v , i) => {
                return new mongoose.Types.ObjectId(v as string)
            })
            const servicesDocs = await serviceModel.aggregate([
                {
                    $match: {
                        _id: { $in : ids }
                    }
                },
                {
                    $group: {
                        _id: null,
                        totalPrice: {
                            $sum: "$price"
                        }
                    }
                }
            ])
            const payMonth : number = servicesDocs[0] ? servicesDocs[0].totalPrice : 0
            // declare needed variables
            let current_date = new Date(),
            current_date_unix = Math.floor(Date.now() / 1000),
            planDelay_unix = planDelay ? planDelay * 2592000: 0 * 2592000,
            planExpAt = new Date((current_date_unix + planDelay_unix) * 1000);
            // save the doc
            const doc = await memberModel.findByIdAndUpdate( _id , {
                bodyState,
                services,
                payMonth,            
                planUpdatedAt: current_date.toUTCString(),
                planUpdatedAt_unix: current_date_unix,
                planDelay,
                planDelay_unix: planDelay_unix,    
                planExpAt: planExpAt.toUTCString(),
                planExpAt_unix: current_date_unix + planDelay_unix,
                active: true,
            } , {
                new: true
            })
            // add the subscription income
            let income = payMonth * planDelay
            await statisticsModel.findOneAndUpdate({} , {
                $inc: {
                    totalIncome: income
                }
            })
            // return the success response
            return NextResponse.json({
                success: true,
                message: "requestTerminatedWithSuccess",
                data: doc,
            }, {
                status: 200,
                headers: {
                    "content-type": "application/json"
                }
            })
        }
    }catch(e)
    {
        // catch any error and return an error response
        return NextResponse.json({
            success: false,
            message: "serverError",
        }, {
            status: 500,
            headers: {
                "content-type": "application/json"
            }
        })
    }
}