import { Role } from "@app/shared/types/roles";
import pool from "../../db";
import { Member, MemberCardDetails, MemberLight, memberSettings, MemberState, PaginatedMembers } from '@app/shared/types/member'
import { logger } from "../logging/logger";
import { memberCache } from "../../routes/auth";
import * as mariadb from 'mariadb';

export async function getFilteredMembers(
    page: number = 1,
    pageSize: number = 15,
    search?: string,
    status?: string,
    unitId?: string
): Promise<PaginatedMembers> {
    try {
        const offset = (page - 1) * pageSize;
        const whereClauses: string[] = [];
        const params: any[] = [];

        if (status && status !== 'all') {
            whereClauses.push(`m.state = ?`);
            params.push(status);
        }

        if (search) {
            whereClauses.push(`v.member_name LIKE ?`);
            params.push(`%${search}%`);
        }

        if (unitId && unitId !== 'all') {
            whereClauses.push(`v.unit = ?`);
            params.push(unitId);
        }

        const whereClause = whereClauses.length > 0
            ? ` WHERE ${whereClauses.join(' AND ')}`
            : '';

        // COUNT QUERY
        const countQuery = `SELECT COUNT(*) as total FROM view_member_rank_unit_status_latest v INNER JOIN members m ON v.member_id = m.id ${whereClause}`;
        const [countResults]: any[] = await pool.query(countQuery, params);
        const total = Number(countResults?.total) || 0;

        // DATA QUERY
        const dataQuery = `
      SELECT 
        v.*,
        CASE 
          WHEN EXISTS (
            SELECT 1 FROM leave_of_absences l 
            WHERE l.member_id = v.member_id 
              AND l.deleted = 0 
              AND UTC_TIMESTAMP() BETWEEN l.start_date AND l.end_date
          ) THEN 1 ELSE 0 
        END AS on_loa
      FROM view_member_rank_unit_status_latest v
      INNER JOIN members m ON v.member_id = m.id
      ${whereClause} -- Added back correctly
      ORDER BY v.member_name ASC
      LIMIT ? OFFSET ?
    `;

        const rows: any[] = await pool.query(dataQuery, [...params, pageSize, offset]);

        // Map rows to Member type
        const members: Member[] = rows.map(row => ({
            member_id: Number(row.member_id),
            member_name: row.member_name,
            displayName: row.displayName,
            rank: row.rank,
            rank_date: row.rank_date,
            unit: row.unit,
            unit_date: row.unit_date,
            status: row.status,
            status_date: row.status_date,
            loa_until: row.loa_until ? new Date(row.loa_until) : undefined,
            member_state: row.member_state
        }));

        return {
            data: members,
            pagination: {
                page,
                pageSize,
                total,
                totalPages: Math.ceil(total / pageSize),
            },
        };
    } catch (error) {
        logger.error('app', 'Error fetching filtered members', {
            error: error instanceof Error ? error.message : String(error),
        });
        throw error;
    }
}

export async function getUserData(userID: number): Promise<Member> {
    const sql = `SELECT * FROM view_member_rank_unit_status_latest WHERE member_id = ?`;
    const res: Member = await pool.query(sql, [userID]);
    return res[0] ?? null;
}

export async function setUserState(userID: number, state: MemberState, reason: string, creatorID: number, externalCon?: mariadb.PoolConnection, details: string = "", endPrevious: boolean = true, createHistory: boolean = true) {
    const isInternalConn = !externalCon;
    if (isInternalConn)
        var con = await pool.getConnection();
    else
        var con = externalCon;

    try {
        if (isInternalConn) await con.beginTransaction();

        if (endPrevious)
            await endLatestMemberState(userID, con);

        const sql = `UPDATE members SET state = ? WHERE id = ?;`;
        await con.query(sql, [state, userID]);

        if (createHistory) {
            const insertHistorySql = `INSERT INTO member_state_history
                (member_id, state_id, reason, created_by_id, start_date, end_date, reason_detailed)
                VALUES (?, ?, ?, ?, NOW(), NULL, ?);`;
            await con.query(insertHistorySql, [userID, state, reason, creatorID, details]);
        }

        if (isInternalConn) await con.commit();
    } catch (error) {
        if (isInternalConn) {
            await con.rollback();
        }
        logger.error('app', 'Error setting user state', error);
        throw error;
    } finally {
        memberCache.Invalidate(userID);
        if (isInternalConn && con) con.release();
    }
}

export async function getUserState(user: number): Promise<MemberState> {
    let out = await pool.query(`SELECT state FROM members WHERE id = ?`, [user]);
    return (out[0].state as MemberState);
}

export async function getMemberSettings(id: number): Promise<memberSettings> {
    const sql = `SELECT * FROM view_member_settings WHERE id = ?`;
    let out: memberSettings[] = await pool.query(sql, [id]);

    if (out.length != 1)
        throw new Error("Could not get user settings");

    return out[0];
}

export async function setUserSettings(id: number, settings: memberSettings) {
    const sql = `UPDATE view_member_settings SET
                displayName = ?
                WHERE id = ?;`;
    let result = await pool.query(sql, [settings.displayName, id])
}

export async function getMembersLite(ids: number[]): Promise<MemberLight[]> {
    const sql = `SELECT m.member_id AS id,
                  m.member_name AS username,
                  m.displayName,
                  u.color
              FROM view_member_rank_unit_status_latest m
                  LEFT JOIN units u ON u.name = m.unit
              WHERE member_id IN (?);`;
    const res: MemberLight[] = await pool.query(sql, [ids]);
    return res;
}

export async function getAllMembersLite(activeOnly: boolean): Promise<MemberLight[]> {

    const filter = activeOnly ? `\nWHERE member_state = ${MemberState.Member}` : ''
    const sql = `SELECT m.member_id AS id,
                  m.member_name AS username,
                  m.displayName,
                  u.color
              FROM view_member_rank_unit_status_latest m
                  LEFT JOIN units u ON u.name = m.unit ${filter};`;
    console.log(sql);
    const res: MemberLight[] = await pool.query(sql);
    return res;
}

export async function getMembersFull(ids: number[]): Promise<MemberCardDetails[]> {
    const sql = `
    SELECT 
        m.*,
        (
            SELECT COALESCE(JSON_ARRAYAGG(JSON_OBJECT(
                'id', r.id,
                'name', r.name,
                'color', r.color,
                'description', r.description
            )), JSON_ARRAY())
            FROM members_roles mr
            JOIN roles r ON mr.role_id = r.id
            WHERE mr.member_id = m.member_id
        ) AS roles
    FROM view_member_rank_unit_status_latest m
    WHERE m.member_id IN (?);
  `;

    const rows: any[] = await pool.query(sql, [ids]);

    return rows.map(row => {
        const member: Member = {
            member_id: row.member_id,
            member_name: row.member_name,
            displayName: row.displayName,
            rank: row.rank,
            rank_date: row.rank_date,
            unit: row.unit,
            unit_date: row.unit_date,
            status: row.status,
            status_date: row.status_date,
            loa_until: row.loa_until ? new Date(row.loa_until) : undefined,
        };
        // roles comes as array of strings; parse each one
        const roles: Role[] = row.roles;

        return { member, roles };
    });
}

export async function mapDiscordtoID(id: number): Promise<number | null> {
    const sql = `SELECT id FROM members WHERE discord_id = ?;`
    let res = await pool.query(sql, [id]);
    return res.length > 0 ? res[0].id : null;
}

export async function endLatestMemberState(memberID: number, con: mariadb.Pool | mariadb.Connection = pool) {
    const sql = `UPDATE member_state_history
                SET end_date = NOW(),
                    updated_at = NOW()
                WHERE id = (
                        SELECT id
                        FROM (
                                SELECT id
                                FROM member_state_history
                                WHERE member_id = ?
                                    AND end_date IS NULL
                                ORDER BY start_date DESC,
                                    created_at DESC
                                LIMIT 1
                            ) AS x
                    );`;

    try {
        let res = await con.query(sql, [memberID]);
        console.log(res);
        return;
    } catch (error) {
        logger.error('app', 'Error ending latest member state', {
            error: error instanceof Error ? error.message : String(error),
        });
        throw error;
    }
    // let res = await pool.query(sql, [memberID]);
    // console.log(res);
}

export async function getLastNonSuspendedState(memberID: number): Promise<MemberState> {
    try {
        const sql = `SELECT state_id 
                        FROM member_state_history 
                        WHERE member_id = ? 
                        AND state_id != ? 
                        ORDER BY start_date DESC, id DESC
                        LIMIT 1;`
        const res = await pool.query(sql, [memberID, MemberState.Suspended]);
        console.log(res as MemberState[])
        if (res.length)
            return res[0].state_id as MemberState;
    } catch (error) {
        logger.error('app', 'Error ending latest member state', {
            error: error instanceof Error ? error.message : String(error),
        });
    }
}