import Console from "../utils/console"
import api from "../utils/api"

import v from "validator"
import { ValidationError, InternalError } from "../utils/errors"

import * as fs from "fs"
import cli from "cli-ux"
import * as storage from "node-persist"

import { IPayload, ISession, IStartProps } from "../models/session"
import { IConfigObj } from "../models/config"
import TelemetryManager from "./telemetry"
import * as path from "path"
import * as os from "os"

const GLOBAL_SESSION_PATH = path.join(os.homedir(), ".learnpack-session")

const Session: ISession = {
  sessionStarted: false,
  token: null,
  config: null,
  currentCohort: null,
  initialize: async function () {
    if (!this.sessionStarted) {
      // Use a system-wide path instead of config.dirPath
      if (!fs.existsSync(GLOBAL_SESSION_PATH)) {
        fs.mkdirSync(GLOBAL_SESSION_PATH, { recursive: true })
      }

      await storage.init({ dir: GLOBAL_SESSION_PATH })
      this.sessionStarted = true
    }

    return true
  },

  setRigoToken: async function (token: string) {
    await this.initialize()
    const payload = await storage.getItem("bc-payload")
    await storage.setItem("bc-payload", {
      ...payload,
      rigobot: { key: token },
    })
    Console.debug("Rigobot token successfuly set")
    return true
  },
  setTabHash: async function (hash: string) {
    await this.initialize()
    const payload = await storage.getItem("bc-payload")
    await storage.setItem("bc-payload", {
      ...payload,
      tabHash: hash,
    })
    Console.debug("tabHash successfuly set")
    return true
  },
  setSessionKey: async function (value: string) {
    await this.initialize()
    const payload = await storage.getItem("bc-payload")
    await storage.setItem("bc-payload", {
      ...payload,
      sessionKey: value,
    })
    Console.debug("sessionKey successfuly set")
    return true
  },
  setPayload: async function (value: IPayload) {
    await this.initialize()
    await storage.setItem("bc-payload", { ...value })
    Console.debug(
      "Payload successfuly found and set for user " + value.user_id
    )

    // TelemetryManager.setStudent({
    //   user_id: value.user_id.toString(),
    //   email: value.email,
    //   token: value.token,
    // })

    return true
  },
  getPayload: async function () {
    await this.initialize()
    let payload = null
    try {
      payload = await storage.getItem("bc-payload")
    } catch {
      Console.debug("Error retriving session payload")
    }

    return payload
  },
  isActive: function () {
    return !!this.token
  },
  get: async function (configObj?: IConfigObj) {
    if (configObj && configObj.config) {
      this.config = configObj.config
    }

    await this.sync()
    if (!this.isActive()) {
      return null
    }

    const payload = await this.getPayload()

    return {
      payload,
      token: this.token,
    }
  },
  login: async function () {
    const email = await cli.prompt("What is your email?")
    if (!v.isEmail(email)) {
      throw ValidationError("Invalid email")
    }

    const password = await cli.prompt("What is your password?", {
      type: "hide",
    })

    const data = await api.login(email, password)

    if (data) {
      Console.debug("Login successfull")
      // cli.log(data)
      await this.start({ token: data.token, payload: data })
      return data
    }
  },
  loginWeb: async function (email, password) {
    if (!v.isEmail(email)) {
      throw ValidationError("Invalid email")
    }

    const data = await api.login(email, password)
    if (data) {
      this.start({ token: data.token, payload: data })

      return data
    }
  },
  sync: async function () {
    const payload = await this.getPayload()
    if (payload) {
      this.token = payload.token
    }
  },
  start: async function ({ token, payload = null }: IStartProps) {
    if (!token) {
      throw new Error("A token and email is needed to start a session")
    }

    this.token = token

    if (payload && (await this.setPayload(payload))) {
      Console.success(`Successfully logged in as user ${payload.user_id}`)
    }
  },
  destroy: async function () {
    if (!this.sessionStarted) {
      await this.initialize()
    }

    await storage.clear()
    this.token = null
    Console.success("You have logged out")
  },
  breakToken: async function () {
    const payload = await this.getPayload()
    if (payload) {
      this.token = "asdasdasdasd"
      await storage.setItem("bc-payload", {
        ...payload,
        token: "asdasdsad",
      })
      Console.success("Token broken successfully")
    }
  },
}

export default Session
