from sqlalchemy import desc, func, asc
import datetime

from app.main.data_model.games.finedge.fe_asset import FEAsset
from app.main.data_model.games.finedge.fe_intraday_data import FEIntraDayData
from app.main.data_model.games.finedge.fe_market_intraday_data import FEMarketIntraDayData


class FEIntraDayDataRepository:
    def __init__(self, session):
        self.session = session

    def get_last_performances_by_market_id(self, market_id):
        last_date = self.session.query(func.max(FEIntraDayData.loading_date)).first()[0]
        delta = -1
        if last_date is None:
            yesterday = datetime.timedelta(days=delta)
        else:
            if last_date.weekday() == 0:
                delta = -3
            yesterday = last_date + datetime.timedelta(days=delta)
        asset_ids = self.session.query(FEAsset.id).filter(
            FEAsset.market_id == market_id
        ).distinct().all()
        asset_ids = [x[0] for x in asset_ids]
        performances = self.session.query(FEIntraDayData).filter(
            FEIntraDayData.market_date >= yesterday,
            FEIntraDayData.asset_id.in_(asset_ids)).order_by(FEIntraDayData.market_date.desc()).all()
        performances_dict = {}
        for performance in performances:
            if len(performances_dict) == len(asset_ids):
                break
            if performance.asset_id in performances_dict:
                continue
            performances_dict[performance.asset_id] = performance
        return list(performances_dict.values())

    def get_all_last_performances(self, last_date):
        first_last_date = last_date.first()[0]
        delta = -1
        if first_last_date.weekday() == 0:
            delta = -3
        yesterday = first_last_date + datetime.timedelta(days=delta)
        asset_ids = self.session.query(FEAsset.id).distinct().all()
        performances = self.session.query(FEIntraDayData).filter(FEIntraDayData.market_date >= yesterday).\
            order_by(FEIntraDayData.market_date.desc()).all()
        performances_dict = {}
        for performance in performances:
            if len(performances_dict) == len(asset_ids):
                break
            if performance.asset_id in performances_dict:
                continue
            performances_dict[performance.asset_id] = performance
        return list(performances_dict.values())

    def get_last_performances(self, asset_id):
        last_date = self.session.query(func.max(FEIntraDayData.loading_date))
        if asset_id is None:
            return self.get_all_last_performances(last_date)
        else:
            last_date = last_date.filter(FEIntraDayData.asset_id == asset_id)
            performance = self.session.query(FEIntraDayData).filter(FEIntraDayData.loading_date == last_date).\
                filter(FEIntraDayData.asset_id == asset_id).first()
            return [performance]

    def get_highests_and_lowests_by_market_id(self, market_id):
        last_date = self.session.query(func.max(FEIntraDayData.loading_date))
        highests = self.session.query(FEIntraDayData).join(FEAsset).filter(FEIntraDayData.loading_date == last_date,
                                                                           FEAsset.market_id == market_id,
                                                                           FEIntraDayData.asset_id == FEAsset.id).order_by(
            desc(FEIntraDayData.variation)).limit(7).all()
        lowests = self.session.query(FEIntraDayData).join(FEAsset).filter(FEIntraDayData.loading_date == last_date,
                                                                          FEAsset.market_id == market_id,
                                                                          FEIntraDayData.asset_id == FEAsset.id).order_by(
            asc(FEIntraDayData.variation)).limit(7).all()

        return highests, lowests

    def get_intradays(self, asset_id):
        performances = self.session.query(FEIntraDayData)
        if asset_id is None:
            performances = performances.all()
        else:
            performances = performances.filter(FEIntraDayData.asset_id == asset_id).all()
        if len(performances) == 0:
            return []
        return performances

    def get_market_intradays(self, market_id):
        market_performances = self.session.query(FEMarketIntraDayData).filter(
            FEMarketIntraDayData.market_id == market_id
        ).all()
        if len(market_performances) == 0:
            return []
        return market_performances
