import path from "path"
import fs from "fs-extra"
import fg from "fast-glob"
import { Preset, isValidPreset, parseUhePreset, serializePresetToFile } from "./parser.js";
import { SynthNames, detectPresetLibraryLocations } from "./utils/detector.js";
import { Config } from "./config.js";
import chalk from "chalk";

export interface PresetLibrary {
  synth: string;
  rootFolder: string;
  userPresetsFolder: string;
  presetsFolder?: string;
  presets: Preset[];
  favorites: FavoriteFile[]
}

interface FavoriteFile {
  fileName: string;
  presets: Array<{
    name: string;
    path: string;
  }>
}

export interface UheFavoriteFile {
  // Not documenting the properties that are irrelevant to this tool
  "tag-category-fav": {
    [favoriteCategory: string]: UheFavoriteFileEntry[]
  }
}
export interface UheFavoriteFileEntry {
  "db_path": string;
  "name": string;
}

export function loadPresetLibrary(synth: SynthNames, config: Config): PresetLibrary {
  let pattern = config.pattern || '**/*';

  // Detect correct Preset Library Location
  const location = detectPresetLibraryLocations(config).find(el => el.synthName.toLowerCase() === synth.toLowerCase())

  console.log(`> Loading preset library for ${synth} in ${location.root} with pattern "${pattern}"`);

  const presetLibrary: PresetLibrary = {
    synth: location.synthName,
    rootFolder: location.root,
    userPresetsFolder: location.userPresets,
    presetsFolder: location.presets,
    presets: [],
    favorites: [],
  };

  let librarySelector;
  if (pattern.startsWith('/User/')) {
    librarySelector = 'User'
    pattern = pattern.replace('/User/', '')
  } else if (pattern.startsWith('/Local/')) {
    librarySelector = 'Local'
    pattern = pattern.replace('/Local/', '')
  }

  if (pattern === '/**/*') {
    pattern = '**/*'
  }

  pattern = pattern.split('//').join('/')

  // Load preset library
  const libraryPresets = fg.sync([`${pattern}.h2p`], { cwd:  presetLibrary.presetsFolder }).map((el) => {
    return `/Local/${el}`
  })
  if (librarySelector !== 'User') {
    if (libraryPresets.length > 0) {
      for (const presetPath of libraryPresets) {
        try {
          const presetString = fs.readFileSync(path.join(presetLibrary.presetsFolder, presetPath.replace('/Local/', ''))).toString();
          const parsedPreset = parseUhePreset(presetString, presetPath, config.binary)
          if (isValidPreset(parsedPreset)) {
            presetLibrary.presets.push(parsedPreset);
          }
        } catch (err) {
          console.warn(chalk.yellow(`Could not load and parse preset: ${presetPath}`, err))
        }
      }
    } else {
      console.warn(chalk.yellow(`Could not find presets with glob pattern: ${pattern}.h2p in library: ${presetLibrary.presetsFolder}`))
    }
  }

  // Load user preset library
  const userPresets = fg.sync([`${pattern}.h2p`], { 
    cwd: presetLibrary.userPresetsFolder,
    ignore: ['RANDOM/**/*'],
  }).map((el) => {
    return `/User/${el}`
  })
  if (librarySelector !== 'Local') {
    if (userPresets.length > 0) {
      for (const presetPath of userPresets) {
        try {
          const presetString = fs.readFileSync(path.join(presetLibrary.userPresetsFolder, presetPath.replace('/User/', ''))).toString();
          const parsedPreset = parseUhePreset(presetString, presetPath, config.binary)
          if (isValidPreset(parsedPreset)) {
            presetLibrary.presets.push(parsedPreset);
          }
        } catch (err) {
          console.warn(chalk.yellow(`Could not load and parse preset: ${presetPath}`), err)
        }
      }
    } else {
      console.warn(chalk.yellow(`Could not find presets with glob pattern: ${pattern}.h2p in user library: ${presetLibrary.userPresetsFolder}`))
    }
  }

  if (presetLibrary.presets.length === 0) {
    console.error(chalk.red(`Error: No presets found with glob pattern: ${pattern}.h2p in ` + presetLibrary.presetsFolder))
    process.exit(1)
  }

  // Search and load .uhe-fav files
  const favorites = fg.sync([`**/*.uhe-fav`], { cwd: presetLibrary.rootFolder }).sort()
  for (const favoriteFile of favorites) {
    const path = `${presetLibrary.rootFolder}/${favoriteFile}`;
    try {
      const favJson = fs.readJSONSync(path) as UheFavoriteFile
      for (const favCategory in favJson['tag-category-fav']) {
        presetLibrary.favorites.push({
          fileName: favoriteFile,
          presets: favJson['tag-category-fav'][favCategory].map((el) => {
            return {
              name: el.name,
              path: el.db_path,
            }
          })
        })
      }
    } catch (err) {
      console.warn(chalk.yellow(`Could not read / parse: ${path}`), err);
    }
  }

  console.log(`> Found and loaded ${presetLibrary.presets.length} presets and ${presetLibrary.favorites.length} favorite files`);

  return presetLibrary;
}

export function writePresetLibrary(presetLibrary: PresetLibrary) {
  console.log('----------------------------------------------------------------------')
  for (const preset of presetLibrary.presets) {
    const filePath = path.join(presetLibrary.userPresetsFolder, preset.filePath)
    const fileContent = serializePresetToFile(preset)
    fs.outputFileSync(filePath, fileContent)
    console.log(`Written: ${path.normalize(filePath)}`)
  }
}
