import { v4 as uuidv4 } from 'uuid';
import type { CharacterDNA, ConversationProfile } from '../../types/character.js';
import { cloneDNA } from './serializer.js';
import { buildMasterPrompt } from './prompt-builder.js';
import { dataStore } from '../data-store/index.js';

export interface CloneOptions {
  regenerateImages?: boolean;
}

/**
 * Clone an existing character with optional overrides.
 * Deep clones DNA, assigns new UUID v4, applies selective field changes,
 * rebuilds master prompt, copies conversation profile, and saves to data store.
 */
export async function cloneCharacter(
  sourceId: string,
  overrides?: Partial<CharacterDNA>,
  options?: CloneOptions,
): Promise<CharacterDNA> {
  const sourceDNA = await dataStore.getCharacter(sourceId);
  if (!sourceDNA) {
    throw new Error(`Source character not found: ${sourceId}`);
  }

  // Deep clone the source DNA
  const newDNA = cloneDNA(sourceDNA);

  // Apply selective field overrides before setting managed fields
  if (overrides) {
    applyOverrides(newDNA, overrides);
  }

  // Assign new unique ID and timestamps (always override, even if in overrides)
  const newId = uuidv4();
  const now = new Date().toISOString();
  newDNA.id = newId;
  newDNA.createdAt = now;
  newDNA.updatedAt = now;
  newDNA.status = 'creating';

  // Save the new character DNA
  await dataStore.saveCharacter(newDNA);

  // Rebuild and save master prompt from the new DNA
  const masterPrompt = buildMasterPrompt(newDNA);
  await dataStore.saveMasterPrompt(masterPrompt);

  // Deep clone and save conversation profile with updated characterId
  const sourceProfile = await dataStore.getConversationProfile(sourceId);
  if (sourceProfile) {
    const newProfile: ConversationProfile = JSON.parse(JSON.stringify(sourceProfile));
    newProfile.characterId = newId;
    await dataStore.saveConversationProfile(newProfile);
  }

  return newDNA;
}

/**
 * Applies partial overrides to a CharacterDNA object.
 * Merges nested objects shallowly per top-level section.
 * Skips id, createdAt, updatedAt as those are managed by clone logic.
 */
function applyOverrides(dna: CharacterDNA, overrides: Partial<CharacterDNA>): void {
  for (const key of Object.keys(overrides) as Array<keyof CharacterDNA>) {
    if (key === 'id' || key === 'createdAt' || key === 'updatedAt') continue;

    const value = overrides[key];
    if (value !== undefined && typeof value === 'object' && value !== null && !Array.isArray(value)) {
      (dna as any)[key] = { ...(dna as any)[key], ...value };
    } else if (value !== undefined) {
      (dna as any)[key] = value;
    }
  }
}
