import { Injectable } from "@angular/core";
import { RPCSocket } from 'rpclibrary/js/src/Frontend'
import { Auth, User, _Class, FrontcraftFeatureIfc, SomeOf, FrontcraftIfc, } from '../../../../../../backend/Types/Types'
import { hash, IApiService, GuestUser } from './ApiService';
import { LoggerService } from '../LoggerService/logger.service';
import { ConnectedSocket } from 'rpclibrary';
import { async } from '@angular/core/testing';

declare const Cookies

@Injectable()
export class ServerApiService implements IApiService {
    private socket: ConnectedSocket<FrontcraftIfc>
    private auth: Auth
    private privSocket: RPCSocket & SomeOf<FrontcraftFeatureIfc>

    constructor(
        private logger: LoggerService
    ) { }

    getUnprivilegedSocket = (): ConnectedSocket<FrontcraftIfc> => this.socket

    get = <K extends (keyof FrontcraftIfc | keyof FrontcraftFeatureIfc)>(feature: K):
        K extends keyof FrontcraftIfc ? FrontcraftIfc[K] :
        K extends keyof FrontcraftFeatureIfc ? (FrontcraftFeatureIfc[K] | void) :
        never => {

        //@ts-ignore
        return this.socket[feature]
    }

    getCurrentUser = (): User => {
        return GuestUser
    }

    login = async (username: string, password: string): Promise<RPCSocket & SomeOf<FrontcraftFeatureIfc>> => {
        const pwHash = await hash(password)
        let auth
        try {
            auth = await this.socket.UserManager.login(username, pwHash)
        } catch (e) {
            return
        }

        if (!auth) {
            await this.logout()
            throw new Error("Login failed")
        }

        //attach error handler now so failed logins dont trigger reloads
        this.socket.on('error', async (err) => {
            this.logger.log(err);
        })

    }

    async connectShoutbox(callback: Function): Promise<Function> {
        return this.logger.log
    }

    kick = async () => {
    }

    logout = async () => {
        Cookies.remove('token')
        if (this.auth) {
            try {
                await this.socket.UserManager.logout(this.auth.user.username, this.auth.token.value)
            } catch (e) {
                this.logger.warn(e);
            }
        }

        if (this.privSocket) this.privSocket.close()
        this.privSocket = null
        this.auth = null
    }

    initialize = async (): Promise<any> => {
        if (this.socket) {
            this.socket.close()
            this.socket = null
        }

        try {
            let conn = new RPCSocket<FrontcraftIfc>(8080, window.location.hostname)
            conn.on('close', async () => {
            })

            this.socket = await conn.connect()
        } catch (e) {
            this.logger.log(e);
            throw new Error("Websocket cannot connect")
        }
    }

    getAuth = () => this.auth

    async checkLogin(): Promise<boolean> {
        if (!this.auth) return false
        const valid = this.socket.UserManager.checkToken(this.auth.token.value, this.auth.user.rank)
        if (valid) return true
        await this.logout()
        return false
    }
}