// ─── Equipment Crafting System ──────────────────────────────────────────────
// Equipment crafting functions

import type { EquipmentInstance, EquipmentCraftingProgress, AppliedEnchantment } from './types';
import { CRAFTING_RECIPES, canCraftRecipe, type CraftingRecipe } from './data/crafting-recipes';
import { EQUIPMENT_TYPES } from './data/equipment';
import { ok, fail, ErrorCode } from './utils/result';
import type { Result } from './utils/result';
import { HOURS_PER_TICK } from './constants';

const MANA_REFUND_RATE = 0.5;

// ─── Equipment Crafting Validation ──────────────────────────────────────────

export function canStartEquipmentCrafting(
  blueprintId: string,
  hasBlueprint: boolean,
  materials: Record<string, number>,
  currentMana: number,
  currentAction: string
): { canCraft: boolean; reason?: string; recipe?: CraftingRecipe; missingMaterials?: Record<string, number>; missingMana?: number } {
  if (currentAction !== 'meditate') return { canCraft: false, reason: 'Must be in meditate state' };

  const recipe = CRAFTING_RECIPES[blueprintId];
  if (!recipe) return { canCraft: false, reason: 'Invalid blueprint' };
  if (!hasBlueprint) return { canCraft: false, reason: 'Blueprint not acquired' };

  const { canCraft, missingMaterials } = canCraftRecipe(recipe, materials, currentMana);
  if (canCraft) return { canCraft: true, recipe };

  const missingManaAmount = Math.max(0, recipe.manaCost - currentMana);
  return {
    canCraft: false,
    reason: missingManaAmount > 0 ? 'Insufficient mana' : 'Missing materials',
    recipe,
    missingMaterials,
    missingMana: missingManaAmount > 0 ? missingManaAmount : undefined,
  };
}

// ─── Equipment Crafting Execution ───────────────────────────────────────────

export interface CraftingInitResult {
  recipe: CraftingRecipe;
  newMaterials: Record<string, number>;
  manaCost: number;
  progress: EquipmentCraftingProgress;
}

export function initializeEquipmentCrafting(
  blueprintId: string,
  materials: Record<string, number>,
  _currentMana: number
): CraftingInitResult {
  const recipe = CRAFTING_RECIPES[blueprintId];

  const newMaterials = { ...materials };
  for (const [matId, amount] of Object.entries(recipe.materials)) {
    newMaterials[matId] = (newMaterials[matId] || 0) - amount;
    if (newMaterials[matId] <= 0) delete newMaterials[matId];
  }

  return {
    recipe,
    newMaterials,
    manaCost: recipe.manaCost,
    progress: {
      blueprintId,
      equipmentTypeId: recipe.equipmentTypeId,
      progress: 0,
      required: recipe.craftTime,
      manaSpent: recipe.manaCost,
    },
  };
}

// ─── Crafting Progress ──────────────────────────────────────────────────────

export interface CraftingTickResult {
  progress: number;
  isComplete: boolean;
}

export function calculateCraftingTick(currentProgress: number, required: number): CraftingTickResult {
  const progress = currentProgress + HOURS_PER_TICK;
  return { progress, isComplete: progress >= required };
}

// ─── Crafting Completion ───────────────────────────────────────────────────

const BASE_EQUIPMENT_QUALITY = 100;

export function completeEquipmentCrafting(
  blueprintId: string,
  recipe: CraftingRecipe,
  bonusEnchantments: AppliedEnchantment[] = []
): Result<{ instanceId: string; instance: EquipmentInstance; logMessage: string }> {
  const equipType = EQUIPMENT_TYPES[recipe.equipmentTypeId];
  if (!equipType) return fail(ErrorCode.INVALID_EQUIPMENT_TYPE, `Invalid equipment type: ${recipe.equipmentTypeId}`);

  const instanceId = `equip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  const usedCapacity = bonusEnchantments.reduce((sum, e) => sum + e.actualCost, 0);
  return ok({
    instanceId,
    instance: {
      instanceId,
      typeId: recipe.equipmentTypeId,
      name: recipe.name,
      enchantments: bonusEnchantments,
      usedCapacity,
      totalCapacity: equipType.baseCapacity,
      rarity: recipe.rarity,
      quality: BASE_EQUIPMENT_QUALITY,
      tags: [],
    },
    logMessage: `🔨 Crafted ${recipe.name}!`,
  });
}

// ─── Crafting Cancellation ──────────────────────────────────────────────────

export interface CraftingCancelResult {
  manaRefund: number;
  logMessage: string;
}

export function cancelEquipmentCrafting(blueprintId: string, manaSpent: number, currentProgress?: number, requiredProgress?: number): CraftingCancelResult {
  const recipe = CRAFTING_RECIPES[blueprintId];
  if (!recipe) return { manaRefund: 0, logMessage: 'Invalid crafting recipe.' };

  // Refund proportional to remaining progress: unspent portion + half of spent portion
  let refundRate: number;
  if (currentProgress !== undefined && requiredProgress && requiredProgress > 0) {
    const remainingFraction = Math.max(0, (requiredProgress - currentProgress) / requiredProgress);
    // Full refund for unspent progress, flat 50% for spent progress
    refundRate = remainingFraction + (1 - remainingFraction) * MANA_REFUND_RATE;
  } else {
    refundRate = MANA_REFUND_RATE;
  }
  const manaRefund = Math.floor(manaSpent * refundRate);
  return { manaRefund, logMessage: `🚫 Equipment crafting cancelled. Refunded ${manaRefund} mana.` };
}

// ─── Recipe Information ─────────────────────────────────────────────────────

export function getRecipe(blueprintId: string): CraftingRecipe | null {
  return CRAFTING_RECIPES[blueprintId] || null;
}

export function getCraftableRecipes(
  blueprints: string[],
  materials: Record<string, number>,
  currentMana: number
): CraftingRecipe[] {
  const craftable: CraftingRecipe[] = [];
  for (const blueprintId of blueprints) {
    const recipe = CRAFTING_RECIPES[blueprintId];
    if (!recipe) continue;
    if (canCraftRecipe(recipe, materials, currentMana).canCraft) craftable.push(recipe);
  }
  return craftable;
}

// ─── Material Management ────────────────────────────────────────────────────

export function deleteMaterials(materialId: string, amount: number, materials: Record<string, number>): {
  newMaterials: Record<string, number>;
  deleted: number;
} {
  const currentAmount = materials[materialId] || 0;
  const deleted = Math.min(amount, currentAmount);
  const remaining = Math.max(0, currentAmount - amount);
  const newMaterials = { ...materials };
  if (remaining <= 0) {
    delete newMaterials[materialId];
  } else {
    newMaterials[materialId] = remaining;
  }
  return { newMaterials, deleted };
}

export function getMaterialCount(materials: Record<string, number>, materialId: string): number {
  return materials[materialId] || 0;
}

export function addMaterials(materials: Record<string, number>, materialId: string, amount: number): Record<string, number> {
  const newMaterials = { ...materials };
  newMaterials[materialId] = (newMaterials[materialId] || 0) + amount;
  return newMaterials;
}
