import fs from 'fs/promises';
import path from 'path';
import type { CharacterDNA } from '../../types/character.js';
import type { ReferenceRegenerationResult } from '../../types/reference-image.js';
import { buildSubjectDescription, buildCameraSettings } from './prompt-builder.js';
import { queue } from '../queue-system/index.js';

export interface ReferenceAngle {
  name: string;
  filename: string;
  promptModifier: string;
}

export const REFERENCE_ANGLES: ReferenceAngle[] = [
  {
    name: 'Master Portrait',
    filename: 'master.jpg',
    promptModifier: 'front facing portrait, neutral expression, looking directly at camera, head and shoulders framing',
  },
  {
    name: 'Right 45',
    filename: 'right-45.jpg',
    promptModifier: 'right 45 degree angle portrait, face turned slightly to the right, three-quarter view',
  },
  {
    name: 'Left 45',
    filename: 'left-45.jpg',
    promptModifier: 'left 45 degree angle portrait, face turned slightly to the left, three-quarter view',
  },
  {
    name: 'Full Profile',
    filename: 'full-profile.jpg',
    promptModifier: 'full side profile view, 90 degree angle, sharp silhouette',
  },
  {
    name: "Bird's Eye",
    filename: 'bird-eye.jpg',
    promptModifier: "bird's eye view from above, looking up at camera, top-down angle",
  },
  {
    name: 'Full Body',
    filename: 'full-body.jpg',
    promptModifier: 'full body standing pose, head to toe framing, straight posture',
  },
  {
    name: 'Back View',
    filename: 'back-view.jpg',
    promptModifier: 'back view, looking away from camera, rear angle',
  },
];

/**
 * Builds a complete prompt for a specific reference angle using character DNA.
 */
export function buildAnglePrompt(dna: CharacterDNA, angle: ReferenceAngle): string {
  const subject = buildSubjectDescription(dna);
  const camera = buildCameraSettings(dna);
  return `${subject}, ${angle.promptModifier}, ${camera}`;
}

/**
 * Queues all 7 reference image generation tasks for a character.
 * Returns an array of queue task IDs.
 */
export async function generateReferenceImages(characterId: string, dna: CharacterDNA): Promise<string[]> {
  const outputDir = `data/characters/${characterId}/reference-images`;
  const taskIds: string[] = [];

  for (const angle of REFERENCE_ANGLES) {
    const prompt = buildAnglePrompt(dna, angle);
    const item = await queue.add('image_generation', characterId, {
      prompt,
      outputPath: `${outputDir}/${angle.filename}`,
      angleName: angle.name,
      aspectRatio: '1:1',
      isReferenceImage: true,
      model: 'nano-banana-2',
    });
    taskIds.push(item.id);
  }

  return taskIds;
}

/**
 * Backs up existing reference images to a timestamped backup directory.
 * Moves all files from reference-images/ to reference-images-backup-{timestamp}/.
 * Returns the backup directory path, or empty string if no backup was needed.
 */
export async function backupReferenceImages(characterId: string): Promise<string> {
  const refDir = path.join('data', 'characters', characterId, 'reference-images');

  // Check if reference-images directory exists
  try {
    await fs.access(refDir);
  } catch {
    return '';
  }

  // Check if directory has any files
  const files = await fs.readdir(refDir);
  if (files.length === 0) {
    return '';
  }

  // Create backup directory with filesystem-safe ISO timestamp
  const timestamp = new Date().toISOString().replace(/:/g, '-');
  const backupDir = path.join('data', 'characters', characterId, `reference-images-backup-${timestamp}`);

  try {
    await fs.mkdir(backupDir, { recursive: true });
  } catch (err) {
    throw new Error(`Failed to create backup directory: ${backupDir}`);
  }

  // Move all files to backup directory
  for (const file of files) {
    const src = path.join(refDir, file);
    const dest = path.join(backupDir, file);
    await fs.rename(src, dest);
  }

  return backupDir;
}

/**
 * Regenerates all 7 reference images for a character.
 * Backs up existing images first, then queues new generation tasks.
 * Returns a ReferenceRegenerationResult with task IDs and angle statuses.
 */
export async function regenerateReferenceImages(
  characterId: string,
  dna: CharacterDNA,
): Promise<ReferenceRegenerationResult> {
  // Step 1: Backup existing reference images
  const backupDir = await backupReferenceImages(characterId);

  // Step 2: Ensure reference-images directory exists
  const outputDir = `data/characters/${characterId}/reference-images`;
  await fs.mkdir(outputDir, { recursive: true });

  // Step 3: Queue generation tasks for each of the 7 angles
  const taskIds: string[] = [];
  const angles: ReferenceRegenerationResult['angles'] = [];

  for (const angle of REFERENCE_ANGLES) {
    const prompt = buildAnglePrompt(dna, angle);
    const item = await queue.add('image_generation', characterId, {
      prompt,
      outputPath: `${outputDir}/${angle.filename}`,
      angleName: angle.name,
      aspectRatio: '1:1',
      isReferenceImage: true,
      model: 'nano-banana-2',
    });
    taskIds.push(item.id);
    angles.push({
      name: angle.name,
      taskId: item.id,
      status: 'pending',
    });
  }

  // Step 4: Build and return the result
  return {
    characterId,
    taskIds,
    backupDir,
    angles,
  };
}