# Path: webapp/DefaultResponse.py

# 
# Path: modules/game/AnalysedGame.py
# class GameAnalysedGame(NamedTuple('GameAnalysedGame', [
#         ('analysedGame', AnalysedGame),
#         ('game', Game)
#     ])):
#     """
#     Merger of Game and Analysed Game for a merged tensor
#     """
#     def length(self):
#         return self.analysedGame.length()
# 
#     def tensor(self):
#         try:
#             gt = self.game.boardTensorsByPlayerId(self.analysedGame.playerId, safe = False)
#             at = self.analysedGame.tensor()
#             return [
#                 [_1 + _2 for _1, _2 in zip(gt[0], at)],
#                 gt[1]
#             ]
#         except (TypeError, AttributeError):
#             return None
# 
# Path: modules/irwin/PlayerReport.py
# class PlayerReport(NamedTuple('PlayerReport', [
#         ('id', PlayerReportID),
#         ('userId', PlayerID),
#         ('owner', AuthID),
#         ('activation', int),
#         ('gameReports', List[GameReport]),
#         ('date', datetime)
#     ])):
#     @property
#     def playerId(self):
#         return self.userId
# 
#     @staticmethod
#     def new(player: Player, gamesAndPredictions: Iterable[Tuple[AnalysedGame, AnalysedGamePrediction]], owner: AuthID = 'test'):
#         reportId = PlayerReport.makeId()
#         gamesAndPredictions = [(ag, agp) for ag, agp in gamesAndPredictions if agp is not None]
#         gameReports = [GameReport.new(analysedGame, analysedGamePrediction, reportId) for analysedGame, analysedGamePrediction in gamesAndPredictions]
#         return PlayerReport(
#             id=reportId,
#             userId=player.id,
#             owner=owner,
#             activation=PlayerReport.playerPrediction(player, [agp for _, agp in gamesAndPredictions]),
#             gameReports=gameReports,
#             date=datetime.now())
# 
#     @staticmethod
#     def makeId() -> PlayerReportID:
#         return str("%016x" % random.getrandbits(64))
# 
#     @staticmethod
#     def playerPrediction(player: Player, analysedGamePredictions: List[AnalysedGamePrediction]) -> int:
#         sortedGameActivations = sorted([gp.weightedGamePrediction() for gp in analysedGamePredictions], reverse=True)
#         topGameActivations = sortedGameActivations[:ceil(0.15*len(sortedGameActivations))]
#         topGameActivationsAvg = int(np.average(topGameActivations)) if len(topGameActivations) > 0 else 0
# 
#         aboveUpper = len([i for i in sortedGameActivations if i > 90])
#         aboveLower = len([i for i in sortedGameActivations if i > 80])
# 
#         if aboveUpper > 2 and player.gamesPlayed < 500:
#             result = topGameActivationsAvg
#         elif aboveLower > 0:
#             result = min(92, topGameActivationsAvg)
#         else:
#             result = min(62, topGameActivationsAvg)
#         return result
# 
#     def reportDict(self) -> Dict:
#         return {
#             'userId': self.userId,
#             'owner': self.owner,
#             'activation': int(self.activation),
#             'games': [gameReport.reportDict() for gameReport in self.gameReports]
#         }
# 
# Path: modules/auth/Priv.py

# 
# Path: modules/queue/Origin.py
# def maxOrigin(a, b):
# 
# Path: modules/client/Job.py
# class Job(NamedTuple('Job', [
#         ('playerId', PlayerID),
#         ('games', List[Game]),
#         ('analysedPositions', List[AnalysedPosition])
#     ])):
#     @staticmethod
#     def fromJson(json: Dict):
#         try:
#             return JobBSONHandler.reads(json)
#         except KeyError as e:
#             logging.warning(f'Failed convert {json} to Job: {e}')
#             return None
# 
#     def toJson(self):
#         return JobBSONHandler.writes(self)


import logging
import traceback
from flask import Blueprint, Response, request, jsonify, json
from webapp.DefaultResponse import Success, BadRequest, NotAvailable
from modules.game.AnalysedGame import GameAnalysedGame
from modules.irwin.PlayerReport import PlayerReport
from modules.auth.Priv import RequestJob, CompleteJob, PostJob
from modules.queue.Origin import OriginReport, OriginModerator, OriginRandom
from modules.client.Job import Job

    @apiBlueprint.route('/request_job', methods=['GET'])
    @env.auth.authoriseRoute(RequestJob)
    def apiRequestJob(authable):
        engineQueue = env.queue.nextEngineAnalysis(authable.id)
        logging.debug(f'EngineQueue for req {engineQueue}')
        if engineQueue is not None:
            requiredGames = env.gameApi.gamesForAnalysis(engineQueue.id, engineQueue.requiredGameIds)
            requiredGameIds = [g.id for g in requiredGames]

            logging.warning(f'Requesting {authable.name} analyses {requiredGameIds} for {engineQueue.id}')

            job = Job(
                playerId = engineQueue.id,
                games = requiredGames,
                analysedPositions = [])

            logging.info(f'Job: {job}')

            return  Response(
                response = json.dumps(job.toJson()),
                status = 200,
                mimetype = 'application/json')
        return NotAvailable

    @apiBlueprint.route('/complete_job', methods=['POST'])
    @env.auth.authoriseRoute(CompleteJob)
    def apiCompleteJob(authable):
        req = request.get_json(silent=True)
        try:

# Path: webapp/DefaultResponse.py

# 
# Path: modules/game/AnalysedGame.py
# class GameAnalysedGame(NamedTuple('GameAnalysedGame', [
#         ('analysedGame', AnalysedGame),
#         ('game', Game)
#     ])):
#     """
#     Merger of Game and Analysed Game for a merged tensor
#     """
#     def length(self):
#         return self.analysedGame.length()
# 
#     def tensor(self):
#         try:
#             gt = self.game.boardTensorsByPlayerId(self.analysedGame.playerId, safe = False)
#             at = self.analysedGame.tensor()
#             return [
#                 [_1 + _2 for _1, _2 in zip(gt[0], at)],
#                 gt[1]
#             ]
#         except (TypeError, AttributeError):
#             return None
# 
# Path: modules/irwin/PlayerReport.py
# class PlayerReport(NamedTuple('PlayerReport', [
#         ('id', PlayerReportID),
#         ('userId', PlayerID),
#         ('owner', AuthID),
#         ('activation', int),
#         ('gameReports', List[GameReport]),
#         ('date', datetime)
#     ])):
#     @property
#     def playerId(self):
#         return self.userId
# 
#     @staticmethod
#     def new(player: Player, gamesAndPredictions: Iterable[Tuple[AnalysedGame, AnalysedGamePrediction]], owner: AuthID = 'test'):
#         reportId = PlayerReport.makeId()
#         gamesAndPredictions = [(ag, agp) for ag, agp in gamesAndPredictions if agp is not None]
#         gameReports = [GameReport.new(analysedGame, analysedGamePrediction, reportId) for analysedGame, analysedGamePrediction in gamesAndPredictions]
#         return PlayerReport(
#             id=reportId,
#             userId=player.id,
#             owner=owner,
#             activation=PlayerReport.playerPrediction(player, [agp for _, agp in gamesAndPredictions]),
#             gameReports=gameReports,
#             date=datetime.now())
# 
#     @staticmethod
#     def makeId() -> PlayerReportID:
#         return str("%016x" % random.getrandbits(64))
# 
#     @staticmethod
#     def playerPrediction(player: Player, analysedGamePredictions: List[AnalysedGamePrediction]) -> int:
#         sortedGameActivations = sorted([gp.weightedGamePrediction() for gp in analysedGamePredictions], reverse=True)
#         topGameActivations = sortedGameActivations[:ceil(0.15*len(sortedGameActivations))]
#         topGameActivationsAvg = int(np.average(topGameActivations)) if len(topGameActivations) > 0 else 0
# 
#         aboveUpper = len([i for i in sortedGameActivations if i > 90])
#         aboveLower = len([i for i in sortedGameActivations if i > 80])
# 
#         if aboveUpper > 2 and player.gamesPlayed < 500:
#             result = topGameActivationsAvg
#         elif aboveLower > 0:
#             result = min(92, topGameActivationsAvg)
#         else:
#             result = min(62, topGameActivationsAvg)
#         return result
# 
#     def reportDict(self) -> Dict:
#         return {
#             'userId': self.userId,
#             'owner': self.owner,
#             'activation': int(self.activation),
#             'games': [gameReport.reportDict() for gameReport in self.gameReports]
#         }
# 
# Path: modules/auth/Priv.py

# 
# Path: modules/queue/Origin.py
# def maxOrigin(a, b):
# 
# Path: modules/client/Job.py
# class Job(NamedTuple('Job', [
#         ('playerId', PlayerID),
#         ('games', List[Game]),
#         ('analysedPositions', List[AnalysedPosition])
#     ])):
#     @staticmethod
#     def fromJson(json: Dict):
#         try:
#             return JobBSONHandler.reads(json)
#         except KeyError as e:
#             logging.warning(f'Failed convert {json} to Job: {e}')
#             return None
# 
#     def toJson(self):
#         return JobBSONHandler.writes(self)


# Path: webapp/controllers/api/blueprint.py
import logging
import traceback
from flask import Blueprint, Response, request, jsonify, json
from webapp.DefaultResponse import Success, BadRequest, NotAvailable
from modules.game.AnalysedGame import GameAnalysedGame
from modules.irwin.PlayerReport import PlayerReport
from modules.auth.Priv import RequestJob, CompleteJob, PostJob
from modules.queue.Origin import OriginReport, OriginModerator, OriginRandom
from modules.client.Job import Job


    @apiBlueprint.route('/request_job', methods=['GET'])
    @env.auth.authoriseRoute(RequestJob)
    def apiRequestJob(authable):
        engineQueue = env.queue.nextEngineAnalysis(authable.id)
        logging.debug(f'EngineQueue for req {engineQueue}')
        if engineQueue is not None:
            requiredGames = env.gameApi.gamesForAnalysis(engineQueue.id, engineQueue.requiredGameIds)
            requiredGameIds = [g.id for g in requiredGames]

            logging.warning(f'Requesting {authable.name} analyses {requiredGameIds} for {engineQueue.id}')

            job = Job(
                playerId = engineQueue.id,
                games = requiredGames,
                analysedPositions = [])

            logging.info(f'Job: {job}')

            return  Response(
                response = json.dumps(job.toJson()),
                status = 200,
                mimetype = 'application/json')
        return NotAvailable

    @apiBlueprint.route('/complete_job', methods=['POST'])
    @env.auth.authoriseRoute(CompleteJob)
    def apiCompleteJob(authable):
        req = request.get_json(silent=True)
        try:

            job = Job.fromJson(req['job'])