import path = require("path")

import Console from "./console"
import fs = require("fs")
import { IExercise, IExerciseData } from "../models/exercise-obj"
import { IConfigObj } from "../models/config"
import SessionManager from "../managers/session"
import { fillSidebarJSON } from "./rigoActions"

type TTitleTranslations = {
  [key: string]: string
}

export type TSidebar = {
  [key: string]: TTitleTranslations
}

export const generateSidebar = (exercises: IExercise[], learnPath: string) => {
  const sidebarPath = path.join(learnPath, "sidebar.json")
  let sidebar: TSidebar = {}
  if (fs.existsSync(sidebarPath)) {
    sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"))
  }

  for (const exercise of exercises) {
    sidebar[exercise.slug] = {
      ...sidebar[exercise.slug],
      us: exercise.title,
    }
  }

  fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2))

  return sidebar
}

export const addExerciseToSidebar = (
  exerciseSlug: string,
  targetLanguage: string,
  translatedSlug: string,
  learnPath: string
) => {
  const sidebarPath = path.join(learnPath, "sidebar.json")
  let sidebar: TSidebar = {}
  if (fs.existsSync(sidebarPath)) {
    sidebar = JSON.parse(fs.readFileSync(sidebarPath, "utf8"))
  }

  sidebar[exerciseSlug] = {
    ...sidebar[exerciseSlug],
    [targetLanguage]: translatedSlug,
  }

  fs.writeFileSync(sidebarPath, JSON.stringify(sidebar, null, 2))

  return sidebar
}

export const checkAndFixSidebar = async (
  configObj: IConfigObj,
  autoFix = false
): Promise<boolean> => {
  if (
    configObj.config &&
    fs.existsSync(configObj.config.dirPath + "/sidebar.json")
  ) {
    let hasErrors = false
    const sidebar = fs.readFileSync(
      configObj.config.dirPath + "/sidebar.json",
      "utf8"
    )
    // parse the sidebar.json file
    const sidebarJson = JSON.parse(sidebar)

    const exerciseTranslations: Set<string> = new Set()
    configObj.exercises?.map(e =>
      // eslint-disable-next-line
      Object.keys((e.translations || {}) as any).forEach((t) =>
        exerciseTranslations.add(t)
      )
    )
    // Validation
    for (const [key, value] of Object.entries(sidebarJson) as [
      string,
      TTitleTranslations
    ][]) {
      for (const lang of exerciseTranslations) {
        if (!Object.prototype.hasOwnProperty.call(value, lang)) {
          hasErrors = true
        }
      }
    }

    if (hasErrors && autoFix) {
      Console.warning("Filling sidebar.json file with missing translations")
      const sessionPayload = await SessionManager.getPayload()

      const rigoToken = sessionPayload.rigobot.key

      if (!rigoToken) {
        Console.error("No Rigobot token found, please login first!")
        return false
      }

      const response = await fillSidebarJSON(rigoToken, {
        needed_translations: JSON.stringify(exerciseTranslations),
        sidebar_json: JSON.stringify(sidebarJson),
      })

      const newSidebarJson = JSON.parse(response.parsed.new_sidebar_file)
      fs.writeFileSync(
        configObj.config.dirPath + "/sidebar.json",
        JSON.stringify(newSidebarJson, null, 4)
      )
      Console.info("Sidebar.json was filled with missing translations")
      return true
    }

    if (hasErrors && !autoFix) {
      return false
    }

    return true
  }

  return false
}

export const checkAndFixSidebarPure = async (
  sidebarJson: Record<string, Record<string, string>>,
  exercises: any[],
  rigoToken: string,
  autoFix = true
): Promise<{
  valid: boolean
  fixedSidebar?: Record<string, Record<string, string>>
}> => {
  const exerciseTranslations: Set<string> = new Set()
  for (const e of exercises) {
    for (const lang of Object.keys(e.translations || {})) {
      exerciseTranslations.add(lang)
    }
  }

  let hasErrors = false
  const fixedSidebar: Record<string, Record<string, string>> = {
    ...sidebarJson,
  }

  for (const exercise of exercises) {
    const slug = exercise.slug
    const existingEntry = fixedSidebar[slug]

    if (!existingEntry) {
      hasErrors = true
      fixedSidebar[slug] = { us: exercise.slug }
      continue
    }

    for (const lang of exerciseTranslations) {
      if (!Object.prototype.hasOwnProperty.call(existingEntry, lang)) {
        hasErrors = true
      }
    }
  }

  if (hasErrors && autoFix) {
    if (!rigoToken) {
      Console.error("No Rigobot token provided!")
      return { valid: false }
    }

    Console.warning(
      "Filling sidebar JSON with missing translations or exercises"
    )

    const response = await fillSidebarJSON(rigoToken, {
      needed_translations: JSON.stringify([...exerciseTranslations]),
      sidebar_json: JSON.stringify(fixedSidebar),
    })

    const newSidebarJson = JSON.parse(response.parsed.new_sidebar_file)

    Console.info("Sidebar JSON was fixed")
    return {
      valid: true,
      fixedSidebar: newSidebarJson,
    }
  }

  return {
    valid: !hasErrors,
    fixedSidebar: hasErrors ? fixedSidebar : undefined,
  }
}
