
import { prop, Ref, mongoose } from '@typegoose/typegoose';
import Hero from '../../db/Hero';
import { PvpDefenseType } from '../../db/PvpDefense';
import PvpHistoryOpp from '../../db/PvpHistoryOpp';
import { PvpSaveDataType } from '../../db/PvpSaveData';
import { PvpSeasonResultType } from '../../db/PvpSeasonResult';
import { getPlvAndScore } from '../../pubUtils/data';
import { RewardInter } from '../../pubUtils/interface';
import { nowSeconds } from '../../pubUtils/timeUtil';

export class DefenseHeroInSaveData {
    @prop({ required: true })
    actorId: number;        // 武将id
    @prop({ required: true })
    ai: number;              // ai逻辑，1-进攻型 2-防守型
    @prop({ required: true })
    dataId: number;
    @prop({ required: true })
    order: number;

    constructor(param: { actorId: number, ai: number, dataId: number, order: number }) {
        this.actorId = param.actorId;
        this.ai = param.ai;
        this.dataId = param.dataId;
        this.order = param.order;
    }
}

// 防守阵容武将
export class DefenseHero extends DefenseHeroInSaveData {

    @prop({ ref: 'Hero', type: mongoose.Schema.Types.ObjectId })
    hero: Ref<Hero>;

    constructor(param: { actorId: number, ai: number, dataId: number, order: number }, heroId: string) {
        super(param);
        this.hero = heroId;
    }

}

// 防守阵容
export class Defense {
    @prop({ required: true })
    warId: number;
    @prop({ required: true })
    buff: number;
    @prop({ required: true, type: DefenseHero, _id: false })
    heroes: DefenseHero[];
    @prop({ required: true })
    score: number;              // 防守阵容的总军功
    @prop({ required: true })
    pLv: number;                // 防守阵容的等级
    
    constructor(heroes: DefenseHero[], scores: number[], warId: number, buff: number) {
        this.heroes = heroes;
        this.score = scores.reduce((pre, cur) => pre + cur, 0);
        let {pLv, score} = getPlvAndScore(scores);
        this.pLv = pLv,
        this.score = score;
        this.warId = warId;
        this.buff = buff;
    }
}

// 挑战阵容武将
export class AttackHero {
    @prop({ required: true })
    actorId: number;        // 武将id
    @prop({ required: true })
    order: number;
}

// 挑战阵容
export class Attack {
    @prop({ required: true, type: AttackHero, _id: false })
    heroes: AttackHero[];
    @prop({ required: true })
    score: number;              // 防守阵容的总军功
    @prop({ required: true })
    pLv: number;                // 防守阵容的等级

    constructor(heroes: AttackHero[], scores: number[]) {
        this.heroes = heroes;
        this.score = scores.reduce((pre, cur) => pre + cur, 0);
        let {pLv, score} = getPlvAndScore(scores);
        this.pLv = pLv;
        this.score = score;
    }
}

// 两个阵容中的武将的分别的战力
export class LineupCe {
    @prop({ required: true })
    hid: number;              // 武将id
    @prop({ required: true })
    ce: number;               // 战力
}

export class OppPlayer {
    @prop({ required: true })
    roleId: string;
    @prop({ ref: () => PvpHistoryOpp, type: mongoose.Schema.Types.ObjectId })
    oppDef: Ref<PvpHistoryOpp>;
    @prop({ required: true })
    pos: number;
    @prop({ required: true })
    isRobot: boolean;
}

export class HeroScore {
    @prop({ required: true })
    hid: number;
    @prop({ required: true })
    score: number;
}

export class Reward {
    @prop({ required: true })
    id: number;
    @prop({ required: true })
    count: number;
}

export class HeroReward {
    @prop({ required: true })
    hid: number;
    @prop({ required: true })
    id: number;
    @prop({ required: true })
    count: number;
}

export class OppPlayerReturn {
    pos: number;
    roleId: string;
    roleName: string;
    head: number;
    frame: number;
    spine: number;
    lv: number;
    pLv: number;
    defCe: number;
    rankLv: number;
    addScore: number;
    plusScore: number;
}

// 防守阵容武将
export class DefenseHeroReturn {
    actorId: number;        // 武将id
    ai: number;              // ai逻辑，1-进攻型 2-防守型
    dataId: number;
    order: number;

    constructor(defenseHero: DefenseHero) {
        this.actorId = defenseHero.actorId;
        this.ai = defenseHero.ai;
        this.dataId = defenseHero.dataId;
        this.order = defenseHero.order;
    }
}

export class DefenseLineupReturn {
    warId: number;
    buff: number;
    heroes: DefenseHeroReturn[];
    score: number;
    pLv: number;
    ce: number;

    constructor(defense: Defense, defenseCe: number) {
        this.warId = defense.warId;
        this.buff = defense.buff;
        this.heroes = defense.heroes.map(cur => new DefenseHeroReturn(cur));
        this.score = defense.score;
        this.pLv = defense.pLv;
        this.ce = defenseCe;
    }
}

export class AttackLineupReturn {
    heroes: AttackHero[];
    score: number;
    pLv: number;
    ce: number;

    constructor(attack: Attack, attackCe: number) {
        this.heroes = attack.heroes;
        this.score = attack.score;
        this.pLv = attack.pLv;
        this.ce = attackCe;
    }
}

export class HeroScoreReturn extends HeroScore {
    isDefense: boolean = false;
    constructor(heroScore: HeroScore, defense: Defense) {
        super();
        this.hid = heroScore.hid;
        this.score = heroScore.score;
        if(defense && defense.heroes) {
            let index = defense.heroes.findIndex(cur => cur.actorId == this.hid);
            if(index != -1) {
                this.isDefense = true;
            }
        }
    }
}

export class SeasonDataReturn {
    score: number;
    heroScores: HeroScore[];
    seasonNum: number;
    seasonEndTime: number;
    rankLv: number;

    constructor(pvpSeasonResult: PvpSeasonResultType) {
        this.score = pvpSeasonResult.score;
        this.heroScores = pvpSeasonResult.heroScores;
        this.seasonNum = pvpSeasonResult.seasonNum;
        this.seasonEndTime = pvpSeasonResult.seasonEndTime;
        this.rankLv = pvpSeasonResult.rankLv;
    }
}

export class PvpSeasonResultRecord {
    oldSeasonData: SeasonDataReturn;
    heroGoods: HeroReward[];
    rankGoods: RewardInter[];
    constructor(pvpSeasonResult: PvpSeasonResultType) {
        this.oldSeasonData = new SeasonDataReturn(pvpSeasonResult);
        this.heroGoods = pvpSeasonResult.heroGoods;
        this.rankGoods = pvpSeasonResult.rankGoods;
    }
}

export class PvpDataReturn {
    seasonNum: number;
    seasonStartTime: number;
    seasonEndTime: number;
    seasonRewardTime: number;
    myRank: number = 0;
    oppPlayers: OppPlayerReturn[] = [];
    defense: DefenseLineupReturn = null;
    attack: AttackLineupReturn = null;
    score: number = 0;
    winStreakNum: number = 0;
    refOppCnt: number;
    setAttackCnt: number;
    buyAttackCnt: number;
    challengeCnt: number;
    challengeRefTime: number;
    seasonWinNum: number;
    receivedBox: number[] = [];
    hisScore: number = 0;
    heroScores: HeroScoreReturn[] = [];
    hasSaveDefense: boolean = false;
    resultRecord: PvpSeasonResultRecord;

    setPvpDefense(pvpDefense: PvpDefenseType) {
        this.score = pvpDefense.score;
        this.winStreakNum = pvpDefense.winStreakNum;
        this.seasonWinNum = pvpDefense.seasonWinNum;
        this.receivedBox = pvpDefense.receivedBox;
        this.hisScore = pvpDefense.hisScore;

        this.refOppCnt = pvpDefense.refOppCnt;
        this.setAttackCnt = pvpDefense.setAttackCnt;
        this.buyAttackCnt = pvpDefense.buyAttackCnt;
        this.challengeCnt = pvpDefense.challengeCnt;
        this.challengeRefTime = pvpDefense.challengeRefTime;
        
        let { attackCe, defenseCe } = PvpDataReturn.getAttackAndDefenseCe(pvpDefense);
        if(pvpDefense.attack) this.attack = new AttackLineupReturn(pvpDefense.attack, attackCe);
        if(pvpDefense.defense) this.defense = new DefenseLineupReturn(pvpDefense.defense, defenseCe);
        
        this.heroScores = pvpDefense.heroScores.map(cur => new HeroScoreReturn(cur, pvpDefense.defense));

    }

    static getAttackAndDefenseCe(pvpDefense: PvpDefenseType) {
        let { lineupCe, attack, defense } = pvpDefense;
        let attackCe = 0, defenseCe = 0;
        for(let { hid, ce } of lineupCe) {
            if(attack && attack.heroes) {
                let hero = attack.heroes.find(cur => cur.actorId == hid);
                if(hero) attackCe += ce;
            }
            if(defense && defense.heroes) {
                let hero = defense.heroes.find(cur => cur.actorId == hid);
                if(hero) defenseCe += ce;
            }
        }
        return { attackCe, defenseCe };
    }

    setOppPlayers(oppPlayers: OppPlayerReturn[]) {
        this.oppPlayers = oppPlayers;
    }

    setMyRank(rankLv: number) {
        this.myRank = rankLv;
    }

    setPvpConfig(seasonNum: number, seasonStartTime: number, seasonEndTime: number, seasonRewardTime: number) {
        this.seasonNum = seasonNum;
        this.seasonStartTime = seasonStartTime;
        this.seasonEndTime = seasonEndTime;
        this.seasonRewardTime = seasonRewardTime;
    }

    setPvpSeasonResult(pvpSeasonResult: PvpSeasonResultType) {
        this.resultRecord = new PvpSeasonResultRecord(pvpSeasonResult);
    }

    getHasSaveDefense() {
        if(this.seasonRewardTime < nowSeconds() && this.seasonStartTime > nowSeconds()) {
            return true;
        }
        return !!this.defense;
    }

    calHasSaveDefense() {
        this.hasSaveDefense = this.getHasSaveDefense();
        return this.hasSaveDefense;
    }

    setChallengeCnt(challengeCnt: number) {
        return this.challengeCnt = challengeCnt;
    }
}

export class pvpSaveDataReturn {
    warId: number;    // 地图id
    isUsing: boolean = false; // 设置的是否是这张地图
    hasSet: boolean = false;  // 玩家是否设置过
    buff: number;     // 选择的地图buff，没有设置过不返回
    heroes: DefenseHeroInSaveData[]; // 玩家武将，没有设置不返回

    constructor(warId: number) {
        this.warId = warId;
    }

    setUserSaveData(pvpSaveData: PvpSaveDataType) {
        if(!pvpSaveData) return;
        this.hasSet = true;
        this.buff = pvpSaveData.buff;
        this.heroes = pvpSaveData.heroes;
    }

    setAsUsing() {
        this.isUsing = true;
    }
}