import { resolve } from 'path';
import { rmSync } from 'fs';
import { config } from '../../utils/config.js';
import { createModuleLogger } from '../../utils/logger.js';
import {
  atomicWriteJSON,
  readJSON,
  deleteFile,
  ensureDir,
  listFiles,
  listDirectories,
  fileExists,
} from './file-ops.js';
import type { CharacterDNA, ConversationProfile, ConversationPersona, MasterJSONPrompt } from '../../types/character.js';
import type { ConversationHistory } from '../../types/conversation.js';
import type { StarsTransaction, SceneTemplate } from '../../types/api.js';
import type { TelegramEntity } from '../../types/telegram-entity.js';

const log = createModuleLogger('data-store');

export class DataStore {
  private dataDir: string;

  constructor(dataDir?: string) {
    this.dataDir = dataDir || config.dataDir;
  }

  async init(): Promise<void> {
    const dirs = ['config', 'characters', 'templates', 'queue', 'analytics', 'stars', 'translations', 'logs', 'backups'];
    for (const dir of dirs) {
      await ensureDir(resolve(this.dataDir, dir));
    }
    log.info('Data store initialized');
  }

  // --- Character Operations ---

  private characterDir(id: string): string {
    return resolve(this.dataDir, 'characters', id);
  }

  async saveCharacter(dna: CharacterDNA): Promise<void> {
    const dir = this.characterDir(dna.id);
    await ensureDir(dir);
    await ensureDir(resolve(dir, 'reference-images'));
    await ensureDir(resolve(dir, 'generated-images'));
    await ensureDir(resolve(dir, 'quality-reports'));
    await ensureDir(resolve(dir, 'conversations'));
    await atomicWriteJSON(resolve(dir, 'dna.json'), dna);
  }

  async getCharacter(id: string): Promise<CharacterDNA | null> {
    return readJSON<CharacterDNA>(resolve(this.characterDir(id), 'dna.json'));
  }

  async listCharacters(): Promise<CharacterDNA[]> {
    const dirs = await listDirectories(resolve(this.dataDir, 'characters'));
    const characters: CharacterDNA[] = [];
    for (const dir of dirs) {
      const dna = await this.getCharacter(dir);
      if (dna) characters.push(dna);
    }
    return characters;
  }

  async deleteCharacter(id: string): Promise<boolean> {
    const dir = this.characterDir(id);
    if (!fileExists(dir)) return false;
    rmSync(dir, { recursive: true, force: true });
    return true;
  }

  // --- Master Prompt ---

  async saveMasterPrompt(prompt: MasterJSONPrompt): Promise<void> {
    await atomicWriteJSON(resolve(this.characterDir(prompt.characterId), 'master-prompt.json'), prompt);
  }

  async getMasterPrompt(characterId: string): Promise<MasterJSONPrompt | null> {
    return readJSON<MasterJSONPrompt>(resolve(this.characterDir(characterId), 'master-prompt.json'));
  }

  // --- Conversation Profile ---

  async saveConversationProfile(profile: ConversationProfile): Promise<void> {
    await atomicWriteJSON(resolve(this.characterDir(profile.characterId), 'conversation-profile.json'), profile);
  }

  async getConversationProfile(characterId: string): Promise<ConversationProfile | null> {
    return readJSON<ConversationProfile>(resolve(this.characterDir(characterId), 'conversation-profile.json'));
  }

  // --- Conversation Persona ---

  async saveConversationPersona(characterId: string, persona: ConversationPersona): Promise<void> {
    await atomicWriteJSON(resolve(this.characterDir(characterId), 'conversation-persona.json'), persona);
  }

  async getConversationPersona(characterId: string): Promise<ConversationPersona | null> {
    return readJSON<ConversationPersona>(resolve(this.characterDir(characterId), 'conversation-persona.json'));
  }


  // --- Conversation History ---

  async saveConversationHistory(history: ConversationHistory): Promise<void> {
    const dir = resolve(this.characterDir(history.characterId), 'conversations');
    await ensureDir(dir);
    await atomicWriteJSON(resolve(dir, `${history.telegramUserId}.json`), history);
  }

  async getConversationHistory(characterId: string, userId: number): Promise<ConversationHistory | null> {
    return readJSON<ConversationHistory>(resolve(this.characterDir(characterId), 'conversations', `${userId}.json`));
  }

  async listConversations(characterId: string): Promise<ConversationHistory[]> {
    const dir = resolve(this.characterDir(characterId), 'conversations');
    const files = await listFiles(dir, '.json');
    const histories: ConversationHistory[] = [];
    for (const file of files) {
      const h = await readJSON<ConversationHistory>(resolve(dir, file));
      if (h) histories.push(h);
    }
    return histories;
  }

  async deleteConversation(characterId: string, userId: number): Promise<boolean> {
    return deleteFile(resolve(this.characterDir(characterId), 'conversations', `${userId}.json`));
  }

  // --- Stars Transactions ---

  async saveStarsTransaction(tx: StarsTransaction): Promise<void> {
    const dir = resolve(this.dataDir, 'stars', tx.characterId);
    await ensureDir(dir);
    const txFile = resolve(dir, 'transactions.json');
    const existing = await readJSON<StarsTransaction[]>(txFile) || [];
    existing.push(tx);
    await atomicWriteJSON(txFile, existing);
  }

  async getStarsTransactions(characterId: string): Promise<StarsTransaction[]> {
    return await readJSON<StarsTransaction[]>(resolve(this.dataDir, 'stars', characterId, 'transactions.json')) || [];
  }

  // --- Scene Templates ---

  async saveTemplate(template: SceneTemplate): Promise<void> {
    await atomicWriteJSON(resolve(this.dataDir, 'templates', `${template.id}.json`), template);
  }

  async getTemplate(id: string): Promise<SceneTemplate | null> {
    return readJSON<SceneTemplate>(resolve(this.dataDir, 'templates', `${id}.json`));
  }

  async listTemplates(): Promise<SceneTemplate[]> {
    const files = await listFiles(resolve(this.dataDir, 'templates'), '.json');
    const templates: SceneTemplate[] = [];
    for (const file of files) {
      const t = await readJSON<SceneTemplate>(resolve(this.dataDir, 'templates', file));
      if (t) templates.push(t);
    }
    return templates;
  }

  async deleteTemplate(id: string): Promise<boolean> {
    return deleteFile(resolve(this.dataDir, 'templates', `${id}.json`));
  }

  // --- Reference / Generated Images Paths ---

  getReferenceImagesDir(characterId: string): string {
    return resolve(this.characterDir(characterId), 'reference-images');
  }

  getGeneratedImagesDir(characterId: string): string {
    return resolve(this.characterDir(characterId), 'generated-images');
  }

  getQualityReportsDir(characterId: string): string {
    return resolve(this.characterDir(characterId), 'quality-reports');
  }

  // --- Reference Image URLs ---

  async saveReferenceImageUrls(characterId: string, urls: Record<string, string>): Promise<void> {
    const dir = this.characterDir(characterId);
    await ensureDir(dir);
    await atomicWriteJSON(resolve(dir, 'reference-urls.json'), urls);
  }

  async getReferenceImageUrls(characterId: string): Promise<Record<string, string> | null> {
    return readJSON<Record<string, string>>(resolve(this.characterDir(characterId), 'reference-urls.json'));
  }

  async addReferenceImageUrl(characterId: string, filename: string, url: string): Promise<void> {
    const existing = await this.getReferenceImageUrls(characterId) ?? {};
    existing[filename] = url;
    await this.saveReferenceImageUrls(characterId, existing);
  }

  // --- Channel Config ---

  async saveCharacterChannelConfig(characterId: string, config: unknown): Promise<void> {
    const dir = this.characterDir(characterId);
    await ensureDir(dir);
    await atomicWriteJSON(resolve(dir, 'channel-config.json'), config);
  }

  async getCharacterChannelConfig<T = unknown>(characterId: string): Promise<T | null> {
    return readJSON<T>(resolve(this.characterDir(characterId), 'channel-config.json'));
  }

  // --- Telegram Entities ---

  async getTelegramEntities(characterId: string): Promise<TelegramEntity[]> {
    return await readJSON<TelegramEntity[]>(resolve(this.characterDir(characterId), 'telegram-entities.json')) || [];
  }

}

export const dataStore = new DataStore();
