import { getConnection, getRepository } from 'typeorm';
import { SessionEntity } from '../../entities/session.entity';
import { logSystem, LogSystem } from '../../core/log';
import { GetIPv4Int } from '../utility/GetIPv4Int';
import { FeatureSystem } from '../../core/feature-system';

export class SessionSystem extends FeatureSystem {
    constructor() {
        super();
        mp.events.add('playerQuit', this.playerQuit.bind(this));
    }

    async init(): Promise<void> {
        // Clean up zero-playtime sessions that never got a logout timestamp
        await getConnection()
            .createQueryBuilder()
            .update(SessionEntity)
            .set({ logout: () => 'login' })
            .where('play_time = 0 AND logout IS NULL')
            .execute()
            .catch(() => {});

        super.init('Session system ready');
    }

    async createSession(player: PlayerMp): Promise<void> {
        const ip = player.ip;
        const values = {
            account_id: player.account!.id,
            ip,
            ip_int32: GetIPv4Int(ip),
            ip_int24: GetIPv4Int(ip) >>> 8,
            ip_int16: GetIPv4Int(ip) >>> 16,
            serial: player.socialClub || 'unknown',
            socialclub_id: player.socialClub || 'unknown',
            socialclub_name: player.name,
        };

        const entry = await getConnection()
            .createQueryBuilder()
            .insert()
            .into(SessionEntity)
            .values(values)
            .execute()
            .catch((err) => {
                LogSystem.Error('Session', 'createSession', 'Failed to create session', err, player);
                return null;
            });

        if (!entry || !entry.raw.insertId) {
            player.kick('Server Error (session)');
            return;
        }

        player.session = await getRepository(SessionEntity).findOne({ id: entry.raw.insertId });
    }

    async setSessionCharacter(player: PlayerMp): Promise<void> {
        if (!player.session?.id || !player.character?.id) return;
        await getRepository(SessionEntity)
            .update(player.session.id, { character_id: player.character.id })
            .catch(() => {});
    }

    async playerQuit(player: PlayerMp): Promise<void> {
        if (!player.session?.id) return;

        const loginTime = player.session.login ? new Date(player.session.login).getTime() : Date.now();
        const playTime = Math.floor((Date.now() - loginTime) / 1000);

        await getRepository(SessionEntity)
            .update(player.session.id, {
                logout: () => 'NOW()',
                play_time: playTime,
            })
            .catch(() => {});
    }
}

export const sessionSystem = new SessionSystem();
