import AifexService from "./AifexService";
import BrowserService from "./BrowserService";
import CompatibilityCheck from "./CompatibilityCheck";
import ConnectionCode from "./ConnectionCode";
import Exploration from "./Exploration";
import StateForPopup from "./StateForPopup";
import WebSite from "./Website";
import WindowManager from "./WindowManager";
import StateForTabScript from "./StateForTabScript";
import TabScriptService from "./TabScriptService";
import ChecklistEvaluation from "./ChecklistEvaluation";
import MediaRecorderManager from "./MediaRecorderManager";

export default class Background {
    private _aifexService : AifexService;
    private _browserService : BrowserService;
    private _tabScriptService : TabScriptService;

    private _windowManager: WindowManager;

    private _connectionCode : ConnectionCode;
    private _webSite: WebSite;
    private _sessionBaseURL: string;

	private _testerName: string;
    private _exploration: Exploration;
    private _commentsUp : Array<string>;

    private _isRecording : boolean;
    private _popupCommentPosition : {x:string, y:string};
    private _isTabScriptDisplayingComments : boolean;

    private _screenshotList;

    private _mediaRecordManager : MediaRecorderManager;
    
    constructor(aifexService : AifexService , browserService : BrowserService, tabScriptService : TabScriptService) {
        this._aifexService = aifexService;
        this._browserService = browserService;
        this._tabScriptService = tabScriptService;

        this._windowManager = new WindowManager(browserService);
        this._windowManager.addOnWindoRemovedListener(this.onManagedWindowRemoved.bind(this));

        this._exploration = new Exploration();
        this._testerName = "anonymous";

        this._isRecording = false;
        this._popupCommentPosition = { x:"75%", y:"75%"};
        this._isTabScriptDisplayingComments = false;
        this._commentsUp = [];

        this._screenshotList = [];
        this._mediaRecordManager = new MediaRecorderManager();
    }

    makeCompatibilityCheck() : Promise<CompatibilityCheck> {
        return this._aifexService.getPluginInfo()
            .then((pluginInfo) => {
                return new CompatibilityCheck(this._browserService.getExtensionVesion(), pluginInfo.version, pluginInfo.url);
            })
    }

    connect(connectionCode: ConnectionCode) : Promise<void>{
        //console.log('code:',connectionCode.code);
        this._connectionCode = connectionCode;
        return this._aifexService.getSession(connectionCode.sessionId)
            .then((session) => {
                this._sessionBaseURL = session.baseURL;
                return session.webSiteId
            })
            .then((webSiteId) => {
                return this._aifexService.getWebSite(webSiteId)

            })
            .then((webSite : WebSite) => {
                this._webSite = webSite;
            })
            .then( () => {
                this._windowManager.createConnectedWindow(this._sessionBaseURL);
            })
    }

    disconnect() {
        this._connectionCode = undefined;
        this._sessionBaseURL = undefined;
        this._webSite = undefined;
        return this._windowManager.removeConnectedWindow();
    }
    
    onManagedWindowRemoved() {
        this._connectionCode = undefined;
        this._sessionBaseURL = undefined;
        this._webSite = undefined;
        this._exploration.reset();
        this._commentsUp = [];
        this._isRecording = false;
        this._isTabScriptDisplayingComments = false;
        this._testerName = "anonymous";
        this._screenshotList = [];
    }

    isConnected() : boolean {
        return this._connectionCode !== undefined;
    }

    reloadWebsite() : Promise<void> {
		return this._aifexService.getWebSite(this._webSite.id)
			.then((webSite) => {
                this._webSite = webSite;
            })
            .then((_) => {
                const state = this.getStateForTabScript();
                const tabIds = this._windowManager.getConnectedTabId();
                console.log('background: reload will send:',tabIds);
                return Promise.all(tabIds.map(id => this._tabScriptService.reload(id, state)));
            })
            .then((_) => {});
    }
    
    drawAttention(): Promise<void> {
        if (this._connectionCode) {
            let id = this._windowManager.getConnectedWindowId();
            if (id !== undefined && id !== null) {
                return this._browserService.drawAttentionToWindow(this._windowManager.getConnectedWindowId());
            } else {
                return Promise.resolve();
            }
        } else {
			return Promise.resolve();
		}
	}

    startExploration() : Promise<void> {
        if (!this._isRecording) {
            this._exploration.reset();
            this._exploration.start();
            this._isRecording = true;
            const state = this.getStateForTabScript();
            const tabIds = this._windowManager.getConnectedTabId();
            return Promise.all(tabIds.map(id => this._tabScriptService.startExploration(id, state)))
                .then((_ : Array<void>) => {
                })
        }
    }

    removeExploration() : Promise<void> {
        if (this._isRecording) {
            this._exploration.reset();
            this._isRecording = false;
            const state = this.getStateForTabScript();
            const tabIds = this._windowManager.getConnectedTabId();
            return Promise.all(tabIds.map(id => this._tabScriptService.stopExploration(id, state)))
                .then((_ : Array<void>) => {
                })
        }
    }

    getProbabilities(): Promise<{
		state: StateForTabScript;
		probabilityMap: string;
		followedProbabilityMap: string;
	} | void> {

		if (!this._isRecording || this._exploration.length === 0) {
			return Promise.resolve();
		}

		if (!this._connectionCode) {
			return Promise.reject("Not connected to a model");
		}

		const promises = [];
		promises.push(
			this._aifexService.getProbabilityMap(this._connectionCode, this._exploration)
		);
		return Promise.all(promises)
			.then((resultList) => {
				const [
					probabilityMap,
					followedProbabilityRaw,
				] = resultList;
				let followedProbabilityMap;
				if (followedProbabilityRaw) {
					followedProbabilityMap = followedProbabilityRaw;
				}
				return {
					state: this.getStateForTabScript(),
					probabilityMap,
					followedProbabilityMap,
				};
			})			
    }
    
    getComments(): Promise<{
		state: StateForTabScript;
		commentDistributionList: string;
	} | void> {
		if (!this._isRecording || this._exploration.length === 0 ) {
			return Promise.resolve();
		}

		if (!this._connectionCode) {
			return Promise.reject("Not connected to a model");
		}
		return this._aifexService.getCommentList(this._connectionCode, this._exploration)
			.then((commentDistributionList) => {
                return {
                    commentDistributionList,
                    state: this.getStateForTabScript()
                }
	    	})
    }
    

    addActionToExploration(prefix : string, suffix : string) {
        if (this._isRecording) {
            this._exploration.addAction(prefix, suffix);
            this._commentsUp = [];
        }
    }

    addCommentToExploration(kind : string , message : string) {
        if (this._isRecording) {
            this._exploration.addComment(kind, message);
        }
    }

    upComment(kind : string, message : string) {
        if (this._isRecording) {
            if (!this._commentsUp.includes(message)) {
                this.addCommentToExploration(kind, message);
                this._commentsUp.push(message);
            }
        }
    }


    stopExploration():Promise<void> {
        this._exploration.addAction("end");
        const HAS_MORE_THAN_START_END_ACTIONS = this._exploration.length > 2;
        let sendExplorationPromise;
        if (this._isRecording && HAS_MORE_THAN_START_END_ACTIONS) {
            sendExplorationPromise = this.sendExploration();
        } else {
            sendExplorationPromise = Promise.resolve();
        }
        return sendExplorationPromise           
                .then(() => {
                    this._isRecording = false;
                    this._exploration.reset();
                    this._screenshotList = [];
                    this._commentsUp = [];
                })
                .then(() => {
                    const state = this.getStateForTabScript();
                    const tabIds = this._windowManager.getConnectedTabId();
                    return Promise.all(tabIds.map(id => this._tabScriptService.stopExploration(id, state)))
                })
                .then((_ : Array<void>) => {
                })
    }

    restartExploration(): Promise<void> {
        return this.stopExploration()
            .then(() => {
                this._windowManager.reloadConnectedWindow(this._sessionBaseURL);
            })
			.then(() => {
				return this.startExploration();
			})
			.catch((error) => {
				//TODO disconnect ?
				console.log(error);
			})			
	}


    sendExploration(): Promise<void> {
        const EXPLORATION_CONTAINS_START_ONLY = this._exploration.length === 1;
		if (! this._isRecording ||  EXPLORATION_CONTAINS_START_ONLY) {
			return Promise.resolve();
		}
		
		//const screenshotList = this._screenshotList;

		return this._aifexService.addExploration(
				this._connectionCode,
				this._testerName,
				this._exploration
			)
			.then((explorationNumber) => {
				this._aifexService.addScreenshotList(
					this._connectionCode,
					explorationNumber,
					this._screenshotList
                );
            });
			//	this._tabScriptService.stopTabRecording()
			// 		.then(()=> {
			// 			let video = this.tabService.getTadRecordedMedia();
			// 			console.log('blob',video);
			// 			return this.aifexService.addVideo(
			// 				this.state.connection,
			// 				explorationNumber,
			// 				video
			// 			)
			// 		})
			// })
    }
    
    evaluateChecklist(): Promise<ChecklistEvaluation> {
        return this._aifexService.evaluateSequence(this._connectionCode, this._exploration)
                .then(checklistEvaluation => {
            console.log(checklistEvaluation)
            return checklistEvaluation;
        })
    } 

    changeTesterName(name:string) {
        this._testerName = name;
    }

    setIsTabScriptDisplayingComments(isTabScriptDisplayingComments : boolean) {
        //console.log('displayComments:',isTabScriptDisplayingComments);
        this._isTabScriptDisplayingComments = isTabScriptDisplayingComments;
        const state = this.getStateForTabScript();
        const tabIds = this._windowManager.getConnectedTabId();
        //console.log('background: reload will send:',tabIds);
        Promise.all(tabIds.map(id => this._tabScriptService.reload(id, state)));
    }

    setPopupCommentPosition(position : {x: string, y: string}) {
        this._popupCommentPosition = position;
    }

    getStateForPopup() : StateForPopup {
        let state = new StateForPopup();
        state.connection = this._connectionCode;
        state.isRecording = this._isRecording;
        state.testerName = this._testerName;
        state.isDisplayingComments = this._isTabScriptDisplayingComments;
        state.hasBaseURL = this._sessionBaseURL !== undefined;
        state.managedWindowId = this._windowManager.getConnectedWindowId();
        state.numberOfPerformedInteraction = this._exploration.length;
        return state;
    }

    getStateForTabScript() : StateForTabScript {
        let state = new StateForTabScript();
        state.isRecording = this._isRecording, 
        state.isDisplayingComments = this._isTabScriptDisplayingComments,
        state.webSite = this._webSite;
        state.popupCommentPosition = this._popupCommentPosition;
        return state;
    }

    takeScreenShot(): Promise<void> {
		return this._browserService.takeScreenshot().then(image => {
			this._screenshotList.push({
				image,
				interactionIndex: this._exploration.length - 1,
			});
		})
    }

    setRecordMedia(recordMedia : boolean) {
        if (recordMedia) {
            this._mediaRecordManager.startRecording()
        } else {
            
        }
        if (this._isRecording) {
            this.recordMedia();
        }
    }

    private recordMedia() {
        

    }

}