<script lang="ts">
  import type { PicletInstance } from '$lib/db/schema';
  import type { GradioClient } from '$lib/types';

  interface BattleUpdate {
    battle_updates: string[];
    player_pokemon_status: string;
    player_pokemon_hp: 'Empty' | 'Very Low' | 'Low' | 'Medium' | 'High' | 'Very High' | 'Full';
    enemy_pokemon_status: string;
    enemy_pokemon_hp: 'Empty' | 'Very Low' | 'Low' | 'Medium' | 'High' | 'Very High' | 'Full';
    next_to_act: 'player' | 'enemy';
    available_actions: string[];
  }

  interface Props {
    playerPiclet: PicletInstance;
    enemyPiclet: PicletInstance;
    commandClient: GradioClient;
    onBattleEnd: (winner: 'player' | 'enemy') => void;
    rosterPiclets?: PicletInstance[]; // Optional roster for switching
  }

  let { playerPiclet, enemyPiclet, commandClient, onBattleEnd, rosterPiclets }: Props = $props();

  // Battle state
  let battleState: BattleUpdate = $state({
    battle_updates: [],
    player_pokemon_status: 'Ready for battle',
    player_pokemon_hp: 'Full',
    enemy_pokemon_status: 'Ready for battle', 
    enemy_pokemon_hp: 'Full',
    next_to_act: 'player',
    available_actions: []
  });

  let battleHistory: string[] = $state([]);
  let isProcessing: boolean = $state(false);
  let currentPlayerPiclet: PicletInstance = $state(playerPiclet);
  let showPicletSelector: boolean = $state(false);

  // Dice rolling system
  function rollDice(): number {
    return Math.floor(Math.random() * 20) + 1; // D20 roll
  }

  function getActionEffectiveness(roll: number): { success: string; description: string } {
    if (roll === 20) return { success: 'Critical Success', description: 'The action succeeds spectacularly!' };
    if (roll >= 15) return { success: 'Success', description: 'The action succeeds well!' };
    if (roll >= 10) return { success: 'Partial Success', description: 'The action has some effect.' };
    if (roll >= 5) return { success: 'Failure', description: 'The action fails but something minor happens.' };
    if (roll === 1) return { success: 'Critical Failure', description: 'The action backfires!' };
    return { success: 'Failure', description: 'The action fails.' };
  }

  // Generate text using Command client
  async function generateBattleUpdate(prompt: string): Promise<BattleUpdate> {
    const message = {
      text: prompt,
      files: []
    };

    const result = await commandClient.predict("/chat", {
      message: message,
      max_new_tokens: 1000
    });

    const responseText = result.data || '';
    console.log('LLM Response:', responseText);

    // Extract JSON from response
    try {
      const jsonMatch = responseText.match(/\{[\s\S]*\}/);
      if (!jsonMatch) throw new Error('No JSON found in response');
      
      const battleUpdate: BattleUpdate = JSON.parse(jsonMatch[0]);
      return battleUpdate;
    } catch (error) {
      console.error('Failed to parse battle response:', error);
      // Fallback response
      return {
        battle_updates: ['The battle continues...'],
        player_pokemon_status: battleState.player_pokemon_status,
        player_pokemon_hp: battleState.player_pokemon_hp,
        enemy_pokemon_status: battleState.enemy_pokemon_status,
        enemy_pokemon_hp: battleState.enemy_pokemon_hp,
        next_to_act: battleState.next_to_act === 'player' ? 'enemy' : 'player',
        available_actions: ['Attack', 'Defend', 'Special Move']
      };
    }
  }

  // Initialize battle
  async function startBattle() {
    isProcessing = true;
    
    const initialPrompt = `Let's role play a Pokemon game using my custom Pokemon, the player will use ${currentPlayerPiclet.typeId} and the enemy will use ${enemyPiclet.typeId}.
You will return a brief description on what happens because of the action.
I will send you an update of the enemy or players move and the success of the action (in a DnD style). Be sure to be as creative and engaging as possible when defining battle updates and available actions.

Player Pokemon: ${currentPlayerPiclet.typeId}
${currentPlayerPiclet.description}

Enemy Pokemon: ${enemyPiclet.typeId}
${enemyPiclet.description}

Each response should be a json object with fields:
\`\`\`json
{
    "battle_updates": [list with 1 sentence per entry describing what just happened in battle],
    "player_pokemon_status": "1 sentence description of how the Pokemon is doing",
    "player_pokemon_hp": "enum Empty, Very Low, Low, Medium, High, Very High, Full",
    "enemy_pokemon_status": "1 sentence description of how the Pokemon is doing",
    "enemy_pokemon_hp": "enum Empty, Very Low, Low, Medium, High, Very High, Full",
    "next_to_act": "enum player/enemy",
    "available_actions": ["short list of 1 sentence actions of what to have the next_to_act Pokemon do next"]
}
\`\`\`
Start with just some intro updates describing both monsters being on the battlefield.`;

    try {
      const update = await generateBattleUpdate(initialPrompt);
      battleState = update;
      battleHistory.push(initialPrompt);
    } catch (error) {
      console.error('Failed to start battle:', error);
    }
    
    isProcessing = false;
  }

  // Execute player action
  async function executeAction(actionDescription: string) {
    if (isProcessing) return;
    
    isProcessing = true;
    
    const roll = rollDice();
    const effectiveness = getActionEffectiveness(roll);
    
    const prompt = `Player chooses: "${actionDescription}"
Dice roll: ${roll}/20 (${effectiveness.success})
Effect: ${effectiveness.description}

Update the battle state based on this action and its effectiveness. Then have the enemy take their turn if appropriate.`;

    try {
      const update = await generateBattleUpdate(prompt);
      battleState = update;
      battleHistory.push(prompt);
      
      // Check for battle end conditions
      if (battleState.player_pokemon_hp === 'Empty') {
        onBattleEnd('enemy');
      } else if (battleState.enemy_pokemon_hp === 'Empty') {
        onBattleEnd('player');
      }
    } catch (error) {
      console.error('Failed to execute action:', error);
    }
    
    isProcessing = false;
  }
  
  // Switch Piclet function
  async function switchPiclet(newPiclet: PicletInstance) {
    if (isProcessing) return;
    
    isProcessing = true;
    showPicletSelector = false;
    
    const switchPrompt = `Player switches from ${currentPlayerPiclet.typeId} to ${newPiclet.typeId}!
    
New Pokemon: ${newPiclet.typeId}
${newPiclet.description}

Update the battle to show the switch and have the enemy react accordingly.`;
    
    try {
      currentPlayerPiclet = newPiclet;
      const update = await generateBattleUpdate(switchPrompt);
      battleState = update;
      battleHistory.push(switchPrompt);
    } catch (error) {
      console.error('Failed to switch Piclet:', error);
    }
    
    isProcessing = false;
  }

  // Auto-start battle when component mounts
  $effect(() => {
    startBattle();
  });

  // Export functions for parent component
  export { executeAction, switchPiclet };
</script>

<div class="llm-battle-engine">
  <!-- Battle Narrative Display -->
  <div class="battle-narrative">
    <h3>Battle Progress</h3>
    {#each battleState.battle_updates as update}
      <div class="battle-update">{update}</div>
    {/each}
  </div>
  
  <!-- Pokemon Status -->
  <div class="pokemon-status">
    <div class="player-status">
      <h4>{currentPlayerPiclet.typeId}</h4>
      <div class="hp-indicator hp-{battleState.player_pokemon_hp.toLowerCase().replace(' ', '-')}">{battleState.player_pokemon_hp}</div>
      <p>{battleState.player_pokemon_status}</p>
    </div>
    
    <div class="enemy-status">
      <h4>{enemyPiclet.typeId}</h4>
      <div class="hp-indicator hp-{battleState.enemy_pokemon_hp.toLowerCase().replace(' ', '-')}">{battleState.enemy_pokemon_hp}</div>
      <p>{battleState.enemy_pokemon_status}</p>
    </div>
  </div>
  
  <!-- Available Actions (when it's player's turn) -->
  {#if battleState.next_to_act === 'player' && !isProcessing}
    <div class="available-actions">
      <h4>Choose Your Action:</h4>
      
      <!-- Battle Actions -->
      {#each battleState.available_actions as action}
        <button 
          class="action-button" 
          onclick={() => executeAction(action)}
        >
          {action}
        </button>
      {/each}
      
      <!-- Piclet Switching -->
      {#if rosterPiclets && rosterPiclets.length > 1}
        <button 
          class="switch-button" 
          onclick={() => showPicletSelector = !showPicletSelector}
        >
          🔄 Switch Piclet
        </button>
      {/if}
    </div>
    
    <!-- Piclet Selector -->
    {#if showPicletSelector && rosterPiclets}
      <div class="piclet-selector">
        <h4>Choose Piclet:</h4>
        <div class="piclet-grid">
          {#each rosterPiclets as piclet}
            {#if piclet.id !== currentPlayerPiclet.id}
              <button 
                class="piclet-option" 
                onclick={() => switchPiclet(piclet)}
              >
                <img src={piclet.imageUrl} alt={piclet.typeId} />
                <span>{piclet.typeId}</span>
                <span class="tier tier-{piclet.tier}">{piclet.tier}</span>
              </button>
            {/if}
          {/each}
        </div>
      </div>
    {/if}
  {:else if isProcessing}
    <div class="processing">
      <div class="spinner"></div>
      <p>Processing battle turn...</p>
    </div>
  {:else}
    <div class="enemy-turn">
      <p>Enemy is deciding their move...</p>
    </div>
  {/if}
</div>

<style>
  .llm-battle-engine {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    padding: 1rem;
  }
  
  .battle-narrative {
    background: #f8f9fa;
    border-radius: 8px;
    padding: 1rem;
    max-height: 200px;
    overflow-y: auto;
  }
  
  .battle-update {
    margin-bottom: 0.5rem;
    padding: 0.5rem;
    background: white;
    border-radius: 4px;
    border-left: 3px solid #007bff;
  }
  
  .pokemon-status {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
  }
  
  .player-status, .enemy-status {
    padding: 1rem;
    border-radius: 8px;
    text-align: center;
  }
  
  .player-status {
    background: rgba(0, 123, 255, 0.1);
    border: 2px solid #007bff;
  }
  
  .enemy-status {
    background: rgba(220, 53, 69, 0.1);
    border: 2px solid #dc3545;
  }
  
  .hp-indicator {
    font-weight: bold;
    padding: 0.25rem 0.5rem;
    border-radius: 16px;
    margin: 0.5rem 0;
    display: inline-block;
  }
  
  .hp-full { background: #28a745; color: white; }
  .hp-very-high { background: #40c757; color: white; }
  .hp-high { background: #6bc267; color: white; }
  .hp-medium { background: #ffc107; color: black; }
  .hp-low { background: #fd7e14; color: white; }
  .hp-very-low { background: #dc3545; color: white; }
  .hp-empty { background: #6c757d; color: white; }
  
  .available-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
  }
  
  .action-button {
    padding: 0.75rem 1rem;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.2s;
  }
  
  .action-button:hover {
    background: #0056b3;
  }
  
  .switch-button {
    padding: 0.75rem 1rem;
    background: #28a745;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    font-size: 1rem;
    transition: background-color 0.2s;
    margin-top: 0.5rem;
  }
  
  .switch-button:hover {
    background: #1e7e34;
  }
  
  .piclet-selector {
    background: #f8f9fa;
    border-radius: 8px;
    padding: 1rem;
    margin-top: 1rem;
  }
  
  .piclet-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: 0.5rem;
    margin-top: 0.5rem;
  }
  
  .piclet-option {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    padding: 0.5rem;
    background: white;
    border: 2px solid #dee2e6;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s;
  }
  
  .piclet-option:hover {
    border-color: #007bff;
    background: #f0f7ff;
  }
  
  .piclet-option img {
    width: 40px;
    height: 40px;
    object-fit: cover;
    border-radius: 4px;
  }
  
  .piclet-option span {
    font-size: 0.8rem;
    text-align: center;
  }
  
  .tier {
    padding: 0.1rem 0.3rem;
    border-radius: 8px;
    font-size: 0.7rem;
    font-weight: bold;
    text-transform: uppercase;
  }
  
  .tier-low { background: #6c757d; color: white; }
  .tier-medium { background: #28a745; color: white; }
  .tier-high { background: #fd7e14; color: white; }
  .tier-legendary { background: #dc3545; color: white; }
  
  .processing, .enemy-turn {
    text-align: center;
    padding: 2rem;
  }
  
  .spinner {
    width: 40px;
    height: 40px;
    border: 4px solid #f3f3f3;
    border-top: 4px solid #007bff;
    border-radius: 50%;
    animation: spin 1s linear infinite;
    margin: 0 auto 1rem;
  }
  
  @keyframes spin {
    to { transform: rotate(360deg); }
  }
</style>