import {
takeEvery, put, call, select,
} from 'redux-saga/effects';
/**
* @namespace sagas/live
*/
import Constants, { MATCH_STATUS } from '../constants';
import {
REMOVE_BLINK, SET_BLINK,
SET_LIVE_DATA, GET_SCORES, SETUP_LIVE, GO_TO_MY_LIVE, SHOW_ERROR_MODAL, SETUP_TURBO_LIVE,
} from '../reducers';
import { delay, calulatePlacedSelection } from '../utils/common';
import { parseTimelineResults } from '../utils/parser';
import {
getBlink, getPreviousSecond, getLiveDecrement, getLiveCountdown, getScores,
} from '../store/live';
import { getCurrentPage, getUser } from '../store/common';
import {
getMatches, getTimeline, getHalftimeResults, getResults, getLiveId,
} from '../store/bets';
import { getPlacedSelections, getPlacedSelectionsTurbo } from '../store/placebet';
/**
* Manage sores, track timeline and handle blink goal animations
*
* @memberof sagas/live
* @async
* @param {object} action
* @property {object} action
* @property {object} action.payload
* @property {number} action.payload.endMinute
* @property {number} action.payload.startMinutes
* @property {number} [action.payload.skipBlink] Called after setup live to indicate
* skip blink animation
* @property {object} action.payload.league
* @property {Array} action.payload.leagues
*
*
* @yields {select} getCurrentPage
* @yields {select} getPreviousSecond
* @yields {select} getPlacedSelections
* @yields {select} getBlink
* @yields {select} getScores
* @yields {select} getLiveDecrement
* @yields {select} getLiveCountdown
* @yields {select} getTimeline
* @yields {put} SET_LIVE_DATA
* @yields {put} REMOVE_BLINK
* @yields {put} SHOW_ERROR_MODAL
* @returns {void}
*/
function* getScoresSaga(action) {
try {
let minuteString;
const selectedLeague = action.payload.league;
const leagues = action.payload.leagues;
const startMinutes = action.payload.startMinutes + 1;
const endMinute = action.payload.endMinute;
const currentPage = yield select(getCurrentPage);
const showBlink = Constants.PAGES.ALL_LIVE === currentPage
|| Constants.PAGES.MY_LIVE === currentPage;
let previousSecond = yield select(getPreviousSecond);
let placedSelectionsLive = yield select(getPlacedSelections);
const liveId = yield select(getLiveId);
placedSelectionsLive = placedSelectionsLive[liveId];
const blink = yield select(getBlink);
const scores = yield select(getScores);
const liveDecrement = yield select(getLiveDecrement);
let liveCountdown = yield select(getLiveCountdown);
const timeline = yield select(getTimeline);
let res = {
blink,
scores,
placedSelectionsLive,
blinksForRemove: [],
};
if (liveCountdown > 0) {
liveCountdown -= liveDecrement;
liveCountdown = liveCountdown < 0 ? 0 : liveCountdown;
for (let minute = parseInt(startMinutes);
minute <= parseInt(endMinute); minute += 1) {
for (let i = 0; i < leagues.length; i += 1) {
if (timeline[leagues[i].id]) {
minuteString = timeline[leagues[i].id][minute];
res = parseTimelineResults(
minuteString,
leagues[i].id,
!action.payload.skipBlink
&& (selectedLeague.id === parseInt(leagues[i].id) || showBlink),
res.placedSelectionsLive,
res.blink,
res.scores,
res.blinksForRemove,
);
}
}
previousSecond = minute;
}
yield put({
type: SET_LIVE_DATA,
payload: {
blink: res.blink,
scores: res.scores,
previousSecond,
liveCountdown,
setupLive: true,
liveDecrement,
placedSelections: res.placedSelectionsLive,
roundId: liveId,
},
});
if (res.blinksForRemove.length > 0) {
yield put({
type: REMOVE_BLINK,
payload: {
blinksForRemove: res.blinksForRemove,
},
});
}
}
} catch (error) {
yield put({
type: SHOW_ERROR_MODAL,
payload: {
activeModal: Constants.MODALS.GENERAL_ERROR,
message: error.message,
},
});
}
}
/**
* Calculate coundown and start interval, setup beggining sores and call fun to setup
* placed selections. Also handle showing Live finished modal
*
* @memberof sagas/live
* @async
* @param {object} action
* @property {object} action
* @property {object} action.payload
* @property {number} action.payload.liveMatchDuration
* @property {number} action.payload.liveStart
* @property {Array} action.payload.leagues
* @property {object} action.payload.league
*
* @yields {select} getMatches
* @yields {select} getPlacedSelections
* @yields {put} GO_TO_MY_LIVE
* @yields {put} SET_LIVE_DATA
* @yields {put} GET_SCORES
* @yields {put} SHOW_ERROR_MODAL
* @returns {void}
*/
function* setupLive(action) {
try {
const matches = yield select(getMatches);
const previousSecond = 0;
const liveMatchDuration = action.payload.liveMatchDuration;
const liveDecrement = Constants.REAL_MATCH_DURATION / liveMatchDuration;
const liveStart = action.payload.liveStart;
let liveCountdown = (Math.ceil((liveStart.getTime()
+ ((liveMatchDuration * 1000) - new Date().getTime()))
/ 1000) * liveDecrement) + liveDecrement;
liveCountdown = liveCountdown < 0 ? 0 : liveCountdown;
const scores = {};
const blink = {};
const leagues = action.payload.leagues;
for (let i = 0; i < leagues.length; i += 1) {
if (leagues[i].enabled) {
scores[leagues[i].id] = [];
blink[leagues[i].id] = [];
if (matches[leagues[i].id]) {
for (let j = 0; j < matches[leagues[i].id].length * 2; j += 1) {
scores[leagues[i].id].push(0);
blink[leagues[i].id].push(false);
}
}
}
}
/**
* Calculate coundown and start interval, setup beggining sores and call fun to setup
* placed selections. Also handle showing Live finished modal
*/
let placedSelectionsLive = yield select(getPlacedSelections);
const liveId = yield select(getLiveId);
placedSelectionsLive = placedSelectionsLive[liveId];
const user = yield select(getUser);
if (placedSelectionsLive && user) {
const keys = Object.keys(placedSelectionsLive);
keys.map((league) => {
Object.keys(placedSelectionsLive[league]).map((match) => {
placedSelectionsLive = calulatePlacedSelection(placedSelectionsLive, league, match, '0:0');
});
});
if (keys.length > 0) {
yield put({
type: GO_TO_MY_LIVE,
});
}
}
yield put({
type: SET_LIVE_DATA,
payload: {
blink,
scores,
liveCountdown,
liveDecrement,
previousSecond,
setupLive: true,
placedSelectionsLive,
roundId: liveId,
},
});
yield put({
type: GET_SCORES,
payload: {
startMinutes: -1,
endMinute: (Constants.REAL_MATCH_DURATION - liveCountdown) + liveDecrement,
league: action.payload.league,
leagues,
skipBlink: true,
},
});
} catch (error) {
yield put({
type: SHOW_ERROR_MODAL,
payload: {
activeModal: Constants.MODALS.GENERAL_ERROR,
message: error.message,
},
});
}
}
/**
* Calculate coundown and start interval, setup beggining sores and call fun to setup
* placed selections. Also handle showing Live finished modal
*
* @memberof sagas/live
* @async
* @param {object} action
* @property {object} action
* @property {object} action.payload
* @property {number} action.payload.liveMatchDuration
* @property {number} action.payload.liveStart
* @property {Array} action.payload.leagues
* @property {object} action.payload.league
*
* @yields {select} getMatches
* @yields {select} getPlacedSelections
* @yields {put} GO_TO_MY_LIVE
* @yields {put} SET_LIVE_DATA
* @yields {put} GET_SCORES
* @yields {put} SHOW_ERROR_MODAL
* @returns {void}
*/
function* setupLiveTurbo(action) {
try {
const matches = yield select(getMatches);
const liveMatchDuration = action.payload.liveMatchDuration;
const liveStart = action.payload.liveStart;
const liveCountdown = parseInt((new Date().getTime() - liveStart.getTime()) / 1000)
> parseInt(liveMatchDuration / 2) ? MATCH_STATUS.FULLTIME : MATCH_STATUS.HALFTIME;
const halftimeResults = yield select(getHalftimeResults);
const results = yield select(getResults);
const scores = {};
const leagues = action.payload.leagues;
let placedSelectionsLiveTurbo = yield select(getPlacedSelectionsTurbo);
const liveId = yield select(getLiveId);
placedSelectionsLiveTurbo = placedSelectionsLiveTurbo[liveId];
let placedBetLeagueIds = [];
if (placedSelectionsLiveTurbo) {
placedBetLeagueIds = Object.keys(placedSelectionsLiveTurbo);
}
const leaguesIds = leagues.map((l) => l.id);
// Fill leagues with missing ids.
// Needed when we had bets placed and league is disabled in mean while, before kick off
placedBetLeagueIds.map((leagueId) => {
if (leaguesIds.indexOf(parseInt(leagueId)) === -1) {
leagues.push({ id: parseInt(leagueId), enabled: true });
}
});
for (let i = 0; i < leagues.length; i += 1) {
if (leagues[i].enabled) {
scores[leagues[i].id] = [];
if (matches[leagues[i].id]) {
for (let j = 0; j < matches[leagues[i].id].length * 2; j += 1) {
if (liveCountdown === MATCH_STATUS.HALFTIME) {
scores[leagues[i].id].push(halftimeResults[leagues[i].id][j]);
} else {
scores[leagues[i].id].push(results[leagues[i].id][j]);
}
}
}
}
}
/**
* Calculate coundown and start interval, setup beggining sores and call fun to setup
* placed selections. Also handle showing Live finished modal
*/
if (placedSelectionsLiveTurbo) {
// eslint-disable-next-line sonarjs/no-identical-functions
placedBetLeagueIds.map((league) => {
Object.keys(placedSelectionsLiveTurbo[league]).map((match) => {
const teamHome = match * 2;
const teamAway = (match * 2) + 1;
placedSelectionsLiveTurbo = calulatePlacedSelection(
placedSelectionsLiveTurbo, league, match,
`${scores[league][teamHome]}:${scores[league][teamAway]}`,
);
});
});
if (placedBetLeagueIds.length > 0 && liveCountdown === MATCH_STATUS.HALFTIME) {
yield put({
type: GO_TO_MY_LIVE,
});
}
}
yield put({
type: SET_LIVE_DATA,
payload: {
scores,
liveCountdown,
setupLive: true,
placedSelectionsLiveTurbo,
roundId: liveId,
},
});
} catch (error) {
yield put({
type: SHOW_ERROR_MODAL,
payload: {
activeModal: Constants.MODALS.GENERAL_ERROR,
message: error.message,
},
});
}
}
/**
* Remove all blinks animations from array in 2 seconds
*
* @memberof sagas/live
* @async
* @param {object} action
* @property {object} action
* @property {object} action.payload
* @property {Array} action.payload.blinksForRemove
*
* @yields {call} delay 2000
* @yields {select} getBlink
* @yields {put} SET_BLINK
* @yields {put} SHOW_ERROR_MODAL
* @returns {void}
*/
function* removeBlinks(action) {
try {
yield call(delay, 2000);
const blinksForRemove = action.payload.blinksForRemove;
const blink = yield select(getBlink);
blinksForRemove.map((b) => {
if (blink[b.l]) blink[b.l][b.t] = false;
});
yield put({
type: SET_BLINK,
payload: {
blink,
},
});
} catch (error) {
yield put({
type: SHOW_ERROR_MODAL,
payload: {
activeModal: Constants.MODALS.GENERAL_ERROR,
message: error.message,
},
});
}
}
/**
* @memberof sagas/live
* @async
* @returns {void}
*/
export default function* liveSaga() {
yield takeEvery(GET_SCORES, getScoresSaga);
yield takeEvery(SETUP_LIVE, setupLive);
yield takeEvery(SETUP_TURBO_LIVE, setupLiveTurbo);
yield takeEvery(REMOVE_BLINK, removeBlinks);
}