import {ApiCall} from "tsrpc";
import {PlayerFun} from '../../public/player';
import {ZhanLingTasks} from '../../public/zhanling';
import {ReqOpen, ResOpen} from "../../shared/protocols/ganhai/PtlOpen";
import {PublicShared} from '../../shared/public/public';
import {HongDianChange} from "../hongdian/fun";

export default async function (call: ApiCall<ReqOpen, ResOpen>) {

    let dbData = await G.mongodb.collection('ganhai').findOne({uid: call.uid});

    if (!dbData || dbData.refreshTime < PublicShared.getToDayZeroTime()) {
        let set: any = {
            refreshTime: G.time,
            useFightNum: 0,
            useEscortNum: 0,
            useRefreshNum: 0
        };

        if (!dbData) {
            var shipIndexs = randomMyShips();
            var ships = await randomShips(call.uid, call.conn.gud.ghId);
            set = {
                ...set,
                myShips: shipIndexs,
                ships: ships
            }
        }
        dbData = (await G.mongodb.collection('ganhai').findOneAndUpdate({uid: call.uid}, {$set: set}, {
            upsert: true,
            returnDocument: 'after'
        })).value;
    }

    /**
     * 处理已经被掠夺3次的商船
     */
    let resShips = dbData?.ships
    if (resShips) {
        let npc = []
        let ids = resShips.filter(i => !!i).map(i => {
            let uid = i.player?.player?.uid
            if (uid) return uid
            else npc.push(i)
        })
        let playerDbData = await G.mongodb.collection('ganhai').find({uid: {$in: ids}}).toArray();
        resShips = playerDbData.map(i => i.ship).filter(Boolean)
        resShips = [...resShips, ...npc]
        await G.mongodb.collection('ganhai').updateOne({uid: call.uid}, {$set: {ships: resShips}}, {upsert: true});
    }


    let res: ResOpen = {
        ship: dbData?.ship || null,
        ships: resShips || ships,
        myShips: dbData?.myShips || shipIndexs,
        useFightNum: dbData?.useFightNum || 0,
        useEscortNum: dbData?.useEscortNum || 0,
        useRefreshNum: dbData?.useRefreshNum || 0,
    };

    if (dbData?.ship?.sTime && dbData.ship.sTime + G.gc.ganhai.ships[dbData.ship.index].time < G.time) {
        let prize = calculatePrize(dbData.ship, dbData.ship.sTime + G.gc.ganhai.ships[dbData.ship.index].time);
        await PlayerFun.sendPrize(call, prize);
        dbData.ship = null;
        await G.mongodb.collection('ganhai').updateOne({uid: call.uid}, {$set: {ship: null}}, {upsert: true});
        res.prize = prize;

        GanHaiRed.addList(call.uid, null);
        ZhanLingTasks.addLog(call.uid, 'week', `ganhai_finish`);
        HongDianChange.sendChangeKey(call.uid, ['gonghuihd']);
    }

    call.succ(res);
}

export function randomMyShips(isDj = false, yjdj = false) {
    let shipIndexs: number[] = [];
    for (let i = 0; i < 4; i++) {
        let ship = PublicShared.randomDropAny(G.gc.ganhai.ships);
        shipIndexs.push(G.gc.ganhai.ships.findIndex(s => s.name == ship.name));
    }
    if (isDj) {
        shipIndexs[3] = 3;
    }
    if (yjdj) {
        shipIndexs = [3]
    }
    return shipIndexs;
}

export async function randomShips(uid: string, ghId: string) {
    let gonghui = await G.mongodb.collection('gonghui').findOne({_id: G.mongodb.conversionId(ghId)})

    // todo 用户不存在不属于正常情况，考虑连表性能，先去掉连表查询所有用户
    let ships = await G.mongodb.collection('ganhai').aggregate([
        {
            $match: {
                $and: [
                    {uid: {$nin: [uid, ...gonghui.players.map(i => i.uid)]}},
                    {ship: {$exists: true, $ne: null}},
                    {"ship.beFightNum": {$lt: G.gc.ganhai.beBeatenMax}}]
            }
        },
        {
            $sample: {size: 5}
        }
    ]).toArray()
    return ships.map(s => s.ship)
}

export function calculatePrize(ship: ResOpen['ship'], time: number) {
    let conf = G.gc.ganhai.ships[ship.index];
    let zeroTime = PublicShared.getToDayZeroTime(time);
    let second = time - zeroTime;
    let multiple = 1;

    for (let [start, end] of G.gc.ganhai.doubleTime) {
        if (second >= start && second <= end) {
            multiple = 2;
            break;
        }
    }

    let ratio = conf.ldRatio;
    let ldMultiple = ship.beFightNum * ratio;
    let prize1 = conf.prize.slice(0, 1);
    let prize2 = conf.prize.slice(1);

    let prize = [...prize1, ...prize2.map(atn => {
        let n = atn.n;
        if (ldMultiple > 0) {
            n = atn.n - Math.floor(atn.n * ldMultiple);
        }
        return {...atn, n: n};
    })];

    return prize.filter(p => p.n > 0).map(p => {
        return {...p, n: p.n * multiple};
    });
}

export class GanHaiRed {
    static sends: k_v<boolean> = {};
    static checkList: k_v<ResOpen['ship']> = {};

    static async init() {

        //let dbs = await G.mongodb.collection('ganhai').find({}).toArray();
        //let obj = Object.fromEntries(dbs.map(db => [db.uid, db.ship]));
        let dbs = await G.mongodb.find('ganhai', {}, ['uid', 'ship.sTime', 'ship.index']);
        let obj = Object.fromEntries(dbs.map(db => [db.uid, db.ship]));

        Object.assign(this.checkList, obj);
    }

    static addList(uid: string, ship: ResOpen['ship']) {
        this.checkList[uid] = ship;
        if (ship) {
            this.sends[uid] = false;
        }
    }

    static check() {
        Object.entries(this.checkList).forEach(v => {
            let [uid, ship] = v;
            if (!this.sends[uid] && ship?.sTime && ship?.sTime + G.gc.ganhai.ships[ship.index].time < G.time) {
                G.server.sendMsgByUid(uid, 'msg_s2c/HongDianChange', ['gonghuihd']);
                this.sends[uid] = true;
            }
        });
    }
};