import { BatchPromotion, BatchPromotionMember } from "@app/shared/schemas/promotionSchema";
import { PromotionDetails, PromotionSummary } from "@app/shared/types/rank"
import pool from "../../db";
import { PagedData } from "@app/shared/types/pagination";
import { toDate, toDateIgnoreZone, toDateTime } from "@app/shared/utils/time";
import * as mariadb from 'mariadb';

export async function getAllRanks() {
    const rows = await pool.query(
        'SELECT id, name, short_name, sort_id FROM ranks;'
    );
    return rows;
}

export async function getRankByName(name: string) {
    const rows = await pool.query(`SELECT id, name, short_name, sort_id FROM ranks WHERE name = ?`, [name]);

    if (rows.length === 0)
        throw new Error("Could not find rank: " + name);

    return rows[0];
}

export async function insertMemberRank(member_id: number, rank_id: number, date: Date): Promise<void>;
export async function insertMemberRank(member_id: number, rank_id: number): Promise<void>;

export async function insertMemberRank(member_id: number, rank_id: number, date?: Date): Promise<void> {
    const sql = date
        ? `INSERT INTO members_ranks (member_id, rank_id, start_date) VALUES (?, ?, ?);`
        : `INSERT INTO members_ranks (member_id, rank_id, start_date) VALUES (?, ?, NOW());`;

    const params = date
        ? [member_id, rank_id, date]
        : [member_id, rank_id];

    await pool.query(sql, params);
}


export async function batchInsertMemberRank(promos: BatchPromotionMember[], author: number, approver: number) {
    try {
        var con = await pool.getConnection();
        promos.forEach(p => {
            con.query(`CALL sp_update_member_rank(?, ?, ?, ?, ?, ?)`, [p.member_id, p.rank_id, approver, author, "Rank Change", toDateIgnoreZone(new Date(p.start_date))])
        });

        con.commit();
        return
    } catch (error) {
        throw error; //pass it up
    } finally {
        con.release();
    }
}

export async function getPromotionHistorySummary(page: number = 1, pageSize: number = 15): Promise<PagedData<PromotionSummary>> {

    const offset = (page - 1) * pageSize;

    let sql = `SELECT
                    DATE(start_date) AS entry_day
                FROM
                    members_ranks
                WHERE reason = 'Rank Change'
                GROUP BY
                    entry_day
                ORDER BY
                    entry_day DESC
                LIMIT ? OFFSET ?;`

    let promoList: PromotionSummary[] = await pool.query(sql, [pageSize, offset]) as PromotionSummary[];

    let rowCount = Number((await pool.query(`SELECT
                                                COUNT(*) AS total_grouped_days_count
                                            FROM
                                                (
                                                    SELECT DISTINCT DATE(start_date)
                                                    FROM members_ranks
                                                    WHERE reason = 'Rank Change'
                                                ) AS grouped_days;`))[0]);

    let pageCount = rowCount / pageSize;

    let output: PagedData<PromotionSummary> = { data: promoList, pagination: { page: page, pageSize: pageSize, total: rowCount, totalPages: pageCount } }
    return output;
}

export async function getPromotionsOnDay(day: Date): Promise<PromotionDetails[]> {

    const dayString = toDateTime(day);

    // SQL query to fetch all records from members_unit for the specified day
    let sql = `
        SELECT 
            mr.id AS promo_id,
            mr.member_id,
            mr.created_by_id,
            mr.authorized_by_id,
            r.short_name
        FROM members_ranks AS mr
            LEFT JOIN ranks AS r ON r.id = mr.rank_id
        WHERE DATE(mr.start_date) = ? && mr.reason = 'Rank Change'
        ORDER BY mr.start_date ASC;
    `;

    let batchPromotion = await pool.query(sql, [dayString]) as PromotionDetails[];

    return batchPromotion;
}

export async function cancelLatestRank(userID: number, con: mariadb.Pool | mariadb.Connection = pool): Promise<boolean> {
    try {
        let sql = `CALL sp_end_member_rank(?,NOW())`;
        con.query(sql, [userID]);
        return true;
    } catch (error) {
        throw error;
    }
}