/**
 * @module @bldr/media-manager/location-indicator
 */

// Node packages.
import path from 'path'
import fs from 'fs'

// Project packages.
import config from '@bldr/config'
import { untildify, findParentFile } from '@bldr/core-node'

/**
 * Indicates in which folder structure a file is located.
 *
 * Merge the configurations entries of `config.mediaServer.basePath` and
 * `config.mediaServer.archivePaths`. Store only the accessible ones.
 */
class LocationIndicator {
  /**
   * The base path of the main media folder.
   */
  public main: string

  /**
   * Multiple base paths of media collections (the main base path and some
   * archive base paths)
   */
  public readonly basePaths: string[]

  constructor () {
    this.main = config.mediaServer.basePath
    const basePaths = [
      config.mediaServer.basePath,
      ...config.mediaServer.archivePaths
    ]

    this.basePaths = []
    for (let i = 0; i < basePaths.length; i++) {
      basePaths[i] = path.resolve(untildify(basePaths[i]))
      if (fs.existsSync(basePaths[i])) {
        this.basePaths.push(basePaths[i])
      }
    }
  }

  /**
   * Check if the `currentPath` is inside a archive folder structure and
   * not in den main media folder.
   */
  isInArchive (currentPath: string): boolean {
    if (path.resolve(currentPath).includes(this.main)) {
      return false
    }
    return true
  }

  /**
   * Get the directory where a presentation file (Praesentation.baldr.yml) is
   * located in (The first folder with a prefix like `10_`)
   *
   * `/baldr/media/10/10_Jazz/30_Stile/20_Swing/Material/Duke-Ellington.jpg` ->
   * `/baldr/media/10/10_Jazz/30_Stile/20_Swing`
   */
  getPresParentDir (currentPath: string): string | undefined {
    const parentFile = findParentFile(currentPath, 'Praesentation.baldr.yml')
    if (parentFile != null) {
      return path.dirname(parentFile)
    }
  }

  /**
   * Move a file path into a directory relative to the current
   * presentation directory.
   *
   * `/baldr/media/10/10_Jazz/30_Stile/20_Swing/NB/Duke-Ellington.jpg` `BD` ->
   * `/baldr/media/10/10_Jazz/30_Stile/20_Swing/BD/Duke-Ellington.jpg`
   *
   * @param currentPath - The current path.
   * @param subDir - A relative path.
   */
  moveIntoSubdir (currentPath: string, subDir: string): string {
    const fileName = path.basename(currentPath)
    const presPath = this.getPresParentDir(currentPath)
    if (presPath == null) {
      throw new Error('The parent presentation folder couldn’t be detected!')
    }
    return path.join(presPath, subDir, fileName)
  }

  /**
   * A deactivaed directory is a directory which has no direct counter part in
   * the main media folder, which is not mirrored. It is a real archived folder
   * in the archive folder. Activated folders have a prefix like `10_`
   *
   * true:
   *
   * - `/archive/10/10_Jazz/30_Stile/10_New-Orleans-Dixieland/Material/Texte.tex`
   * - `/archive/10/10_Jazz/History-of-Jazz/Inhalt.tex`
   * - `/archive/12/20_Tradition/30_Volksmusik/Bartok/10_Tanzsuite/Gliederung.tex`
   *
   * false:
   *
   * `/archive/10/10_Jazz/20_Vorformen/10_Worksongs-Spirtuals/Arbeitsblatt.tex`
   */
  isInDeactivatedDir (currentPath: string): boolean {
    currentPath = path.dirname(currentPath)
    const relPath = this.getRelPath(currentPath)
    if (relPath == null) return true
    const segments = relPath.split(path.sep)
    for (const segment of segments) {
      if (segment.match(/^\d\d/) == null) {
        return true
      }
    }
    return false
  }

  /**
   * Get the path relative to one of the base paths and `currentPath`.
   *
   * @param currentPath - The path of a file or a directory inside
   *   a media server folder structure or inside its archive folders.
   */
  getRelPath (currentPath: string): string | undefined {
    currentPath = path.resolve(currentPath)
    let relPath: string | undefined
    for (const basePath of this.basePaths) {
      if (currentPath.indexOf(basePath) === 0) {
        relPath = currentPath.replace(basePath, '')
        break
      }
    }
    if (relPath !== undefined) {
      return relPath.replace(new RegExp(`^${path.sep}`), '')
    }
  }

  /**
   * Get the path relative to one of the base paths and `currentPath`.
   *
   * @param currentPath - The path of a file or a directory inside
   *   a media server folder structure or inside its archive folders.
   */
  getBasePath (currentPath: string): string | undefined {
    currentPath = path.resolve(currentPath)
    let basePath: string | undefined
    for (const bPath of this.basePaths) {
      if (currentPath.indexOf(bPath) === 0) {
        basePath = bPath
        break
      }
    }
    if (basePath !== undefined) {
      return basePath.replace(new RegExp(`${path.sep}$`), '')
    }
  }

  /**
   * The mirrored path of the current give file path, for example:
   *
   * This folder in the main media folder structure
   *
   * `/var/data/baldr/media/12/10_Interpreten/20_Auffuehrungspraxis/20_Instrumentenbau/TX`
   *
   * gets converted to
   *
   * `/mnt/xpsschulearchiv/12/10_Interpreten/20_Auffuehrungspraxis/20_Instrumentenbau`.
   *
   * @param currentPath - The path of a file or a directory inside
   *   a media server folder structure or inside its archive folders.
   */
  getMirroredPath (currentPath: string): string | undefined {



export const locationIndicator = new LocationIndicator()

export default locationIndicator

    const basePath = this.getBasePath(currentPath)
    const relPath = this.getRelPath(currentPath)
    let mirroredBasePath: string | undefined
    for (const bPath of this.basePaths) {
      if (basePath !== bPath) {
        mirroredBasePath = bPath
        break
      }
    }
    if (mirroredBasePath !== undefined && relPath !== undefined) {
      return path.join(mirroredBasePath, relPath)
    }
  }
}