import path from 'path';
import { existsSync, mkdirSync, readFileSync } from 'fs';

export type EngineName = 'yaml' | 'ink' | 'zork' | string;

export interface GameMetadata {
  title: string;
  author?: string;
  subtitle?: string;
  version?: string;
  copyright?: string;
  language?: string;
}

export interface GamePaths {
  mainGameFile: string;
  inkSource?: string;
  inkCompiled?: string;
  promptDir?: string;
  music?: string;
  sfx?: string;
  images?: string;
  [key: string]: string | undefined;
}

export interface GameEngineConfig {
  engine: EngineName;
  locale: 'en_US' | 'de_DE' | string;
  paths: GamePaths;
  metadata: GameMetadata;
}

const PROJECT_ROOT = path.resolve(__dirname, '../..');

function fallbackConfig(engine: EngineName): GameEngineConfig {
  return {
    engine,
    locale: 'en_US',
    paths: {
      mainGameFile:
        engine === 'ink'
          ? 'data/ink/story.ink.json'
          : engine === 'zork'
            ? 'data/z-code/zork1.bin'
            : 'data/worlds/example_world.yml',
      music: 'public/music',
      sfx: 'public/sounds',
      images: 'public/images',
    },
    metadata: {
      title: 'AI Interactive Fiction',
      author: 'Generative AI',
      subtitle: 'An open-world text adventure',
      version: '1.0.0',
      copyright: '',
      language: 'en_US',
    },
  };
}

export function projectPath(relativeOrAbsolutePath: string): string {
  return path.isAbsolute(relativeOrAbsolutePath)
    ? relativeOrAbsolutePath
    : path.resolve(PROJECT_ROOT, relativeOrAbsolutePath);
}

export function loadGameConfig(configPath: string, engine: EngineName): GameEngineConfig {
  const absolutePath = projectPath(configPath);
  if (!existsSync(absolutePath)) {
    console.warn(`[config] Missing ${absolutePath}; using ${engine} defaults.`);
    return fallbackConfig(engine);
  }

  const parsed = JSON.parse(readFileSync(absolutePath, 'utf8')) as Partial<GameEngineConfig>;
  const fallback = fallbackConfig(engine);
  return {
    engine: parsed.engine ?? fallback.engine,
    locale: parsed.locale ?? fallback.locale,
    paths: {
      ...fallback.paths,
      ...(parsed.paths ?? {}),
    },
    metadata: {
      ...fallback.metadata,
      ...(parsed.metadata ?? {}),
      language: parsed.metadata?.language ?? parsed.locale ?? fallback.metadata.language,
    },
  };
}

export function ensureConfiguredAssetDirectories(config: GameEngineConfig): void {
  const directories = [
    config.paths.music,
    config.paths.sfx,
    config.paths.images,
    config.paths.inkSource ? path.dirname(config.paths.inkSource) : undefined,
    config.paths.inkCompiled ? path.dirname(config.paths.inkCompiled) : undefined,
    config.paths.mainGameFile ? path.dirname(config.paths.mainGameFile) : undefined,
    config.paths.promptDir,
  ];

  for (const directory of directories) {
    if (!directory) continue;
    const absolutePath = projectPath(directory);
    if (!existsSync(absolutePath)) {
      mkdirSync(absolutePath, { recursive: true });
    }
  }
}

export function clientGameConfig(config: GameEngineConfig) {
  return {
    engine: config.engine,
    locale: config.locale,
    metadata: config.metadata,
    assets: {
      music: '/music/',
      sfx: '/sounds/',
      sounds: '/sounds/',
      images: '/images/',
    },
  };
}
