import { Component, OnInit } from '@angular/core';
import * as kaplay from "kaplay"
import { MatDialog, MatDialogModule } from '@angular/material/dialog';
import { AtlasMap, Atlas } from './enums/atlas';
import { NightShopComponent } from './shared/night-shop/night-shop.component';
import { CommonModule } from '@angular/common';
import { CountersComponent } from "./shared/counters/counters.component";
import { MachineComponent } from "./shared/machine/machine.component";
import { BubbleTea, Ingredient, NPC, NPCDialogs, Payment, Player, Satisfaction } from './app.model';
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';
import { filter } from 'rxjs';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [
    CommonModule,
    MatDialogModule,
    CountersComponent,
    MachineComponent,
    RouterOutlet
],
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit {
  player: Player = {
    name: 'Player 1',
    money: 0,
    hours: '00:00',
    day: 1,
    ingredients: [],
    finished: false
  };

  previousDay: number = 0;

  ingredients: Ingredient[] = [
    // Liquid ingredients
    { name: 'Lava', value: 50, type: 'liquid', isBlocked: false },
    { name: 'Vanilla', value: 30, type: 'liquid', isBlocked: false },
    { name: 'Cloud', value: 40, type: 'liquid', isBlocked: false },
    { name: 'Strawberry', value: 60, type: 'liquid', isBlocked: false },
  
    // Tapioca ingredients
    { name: 'Diamond', value: 100, type: 'tapioca', isBlocked: false },
    { name: 'Dragon Eye', value: 80, type: 'tapioca', isBlocked: false },
    { name: 'Blueberry', value: 70, type: 'tapioca', isBlocked: false },
    { name: 'Star', value: 90, type: 'tapioca', isBlocked: true }
  ];

  npcs: NPC[] = [];
  bubbleTea: BubbleTea = { container: [] };

  isAppRoute: boolean = false;
  private dialogOpen = false;

  constructor(
    private dialog: MatDialog,
    private router: Router
  ) { }

  ngOnInit(): void {
    this.router.events
      .pipe(filter((event) => event instanceof NavigationEnd))
      .subscribe(() => {
        this.isAppRoute = this.router.url === '/app';

        if (this.isAppRoute) {
          this.gameStart();
        }
      });
  }

  gameStart(): void {
    const k = kaplay.default({
      scale: 4,
      background: [0, 0, 0],
    });

    // Load ATLAS
    k.loadSpriteAtlas(AtlasMap.complete, Atlas);

    // Load Level
    k.loadSprite("wall", AtlasMap.wall);
    k.loadSprite("frame", AtlasMap.frame);
    k.loadSprite("table", AtlasMap.table);
    k.loadSprite("floor", AtlasMap.floor);
    k.loadSprite("shelf", AtlasMap.shelf);
    k.loadSprite("bigplant", AtlasMap.bigplant);
    k.loadSprite("cashregister", AtlasMap.cashregister);
    
    k.add([
      k.sprite("wall"),
      k.scale(2.93),
      k.z(1),
    ]);

    k.add([
      k.sprite("frame"),
      k.scale(2.93),
      k.z(5),
    ]);

    k.add([
      k.sprite("floor"),
      k.scale(2.93),
      k.z(2),
      k.pos(0, 200)
    ]);

    k.add([
      k.sprite("shelf"),
      k.scale(2.93),
      k.z(2),
      k.pos(20, 20)
    ]);

    k.add([
      k.sprite("bigplant"),
      k.scale(2.93),
      k.z(2),
      k.pos(220.5, 95)
    ]);

    k.add([
      k.sprite("cashregister"),
      k.scale(2.93),
      k.z(4),
      k.pos(160, 136)
    ]);

    k.add([
      k.sprite("table"),
      k.scale(2.93),
      k.z(3),
      k.pos(13, 168)
    ]);

    // First op game generate npc
    this.updateNPCsForNewDay();

    k.onUpdate(() => {
      // Nightshop open during night time
      // if (this.isOutsideWorkingHours() && !this.dialogOpen) {
      //   this.openNightShop();
      // } else if (!this.isOutsideWorkingHours() && this.dialogOpen) {
      //   this.closeNightShop();
      // }

      // Generate new customers
      if (this.checkIfDayHasChanged()) {
        this.updateNPCsForNewDay();
      }
    });
  }

  updatePlayerData(eventData: { totalMoney: number; day: number; dateTime: string }): void {
    this.player.money = eventData.totalMoney;
    this.player.day = eventData.day;
    this.player.hours = eventData.dateTime;
  }

  isOutsideWorkingHours(): boolean {
    const workingStart = '07:00';
    const workingEnd = '19:00';
    const playerTime = this.player.hours;

    return playerTime < workingStart || playerTime > workingEnd;
  }

  openNightShop(): void {
    this.dialogOpen = true;
    this.dialog.open(NightShopComponent, {
      width: '400px',
      height: '300px',
      disableClose: true,
      data: { player: this.player }
    });
  }

  closeNightShop(): void {
    if (this.dialogOpen) {
      this.dialog.closeAll();
      this.dialogOpen = false;
    }
  }

  generateBubbleTea(): BubbleTea {
    const randomIngredients = this.getRandomIngredients(this.ingredients, Math.floor(Math.random() * 4) + 1);
    return {
      container: randomIngredients
    };
  }

  submitBubbleTea(selectedIngredients: Ingredient[]): void {
    this.bubbleTea.container = selectedIngredients;
    const npc = this.npcs[0];
    npc.satisfaction = this.calculateSatisfaction(npc, this.bubbleTea);
    const paymentAmount = this.calculatePayment(npc);
    this.player.money += paymentAmount;
    this.npcs.shift();
    this.bubbleTea.container = [];
  }
  
  calculateSatisfaction(npc: NPC, bubbleTea: BubbleTea): Satisfaction {
    const likedIngredients = npc.likedIngredients;
    const selectedIngredients = bubbleTea.container;
  
    const matchingIngredients = selectedIngredients.filter(ingredient =>
      likedIngredients.some(likedIngredient => likedIngredient.name === ingredient.name)
    );
  
    if (matchingIngredients.length === likedIngredients.length && selectedIngredients.length === likedIngredients.length) {
      return 'high';
    } else if (matchingIngredients.length > 0) {
      return 'medium';
    } else {
      return 'low';
    }
  }
  
  calculatePayment(npc: NPC): number {
    switch (npc.satisfaction) {
      case 'high':
        return npc.payment.high;
      case 'medium':
        return npc.payment.medium;
      case 'low':
        return npc.payment.low;
      default:
        return 0;
    }
  }

  updateNPCsForNewDay(): void {
    this.npcs = this.generateNPCs(this.player.day);
  }

  checkIfDayHasChanged(): boolean {
    if (this.player.day > this.previousDay) {
      this.previousDay = this.player.day;
      return true;
    }
    return false;
  }

  generateNPCs(day: number): NPC[] {
    const npcs: NPC[] = [];
    const npcCount = 3 + (day - 1);
  
    for (let i = 0; i < npcCount; i++) {
      const likedIngredients = this.getRandomIngredients(this.ingredients, Math.floor(Math.random() * 4) + 1);
      const npc: NPC = {
        name: `NPC ${i + 1}`,
        likedIngredients: likedIngredients,
        satisfaction: undefined,
        payment: this.generateRandomPayment(),
        dialogs: this.generateNPCDialogs(likedIngredients),
      };
  
      npcs.push(npc);
    }
  
    return npcs;
  }
  
  getRandomIngredients(allIngredients: Ingredient[], count: number): Ingredient[] {
    const unblockedIngredients = allIngredients.filter((ingredient) => !ingredient.isBlocked);
    const tapiocas = unblockedIngredients.filter((ingredient) => ingredient.type === 'tapioca');
    const liquids = unblockedIngredients.filter((ingredient) => ingredient.type === 'liquid');
  
    if (tapiocas.length < 1 || liquids.length < 1) {
      throw new Error('Not enough unblocked tapioca or liquid ingredients to meet the minimum requirements.');
    }
  
    const guaranteedIngredients = [
      this.getRandomSubset(tapiocas, 1)[0],
      this.getRandomSubset(liquids, 1)[0],
    ];
  
    const additionalIngredients = this.getRandomSubset(
      unblockedIngredients.filter((ingredient) => !guaranteedIngredients.includes(ingredient)),
      count - guaranteedIngredients.length
    );
  
    const finalIngredients = [...guaranteedIngredients, ...additionalIngredients];
  
    if (!finalIngredients.some((ingredient) => ingredient.type === 'liquid')) {
      finalIngredients.push(liquids[0]);
    }

    if (finalIngredients.length === 1) {
      return finalIngredients;
    }
  
    return finalIngredients.slice(0, count);
  }
  
  getRandomSubset<T>(array: T[], count: number): T[] {
    const shuffled = [...array].sort(() => 0.5 - Math.random());
    return shuffled.slice(0, count);
  }
  
  getRandomSatisfaction(): Satisfaction {
    const satisfactions: Satisfaction[] = ['low', 'medium', 'high'];
    return satisfactions[Math.floor(Math.random() * satisfactions.length)];
  }
  
  generateRandomPayment(): Payment {
    return {
      low: Math.floor(Math.random() * 10) + 1,
      medium: Math.floor(Math.random() * 20) + 10,
      high: Math.floor(Math.random() * 30) + 20
    };
  }
  
  generateNPCDialogs(likedIngredients: Ingredient[]): NPCDialogs {
    const clues = likedIngredients.map(ingredient => {
      if (ingredient.type === 'liquid') {
        return this.generateLiquidClue(ingredient.name);
      } else if (ingredient.type === 'tapioca') {
        return this.generateTapiocaClue(ingredient.name);
      }
      return '';
    });
  
    const entryDialog = `Hi there! ${clues.join(' ')} What can you make for me today?`;
  
    return {
      low: 'Hmm, this isn’t quite what I was hoping for...',
      medium: 'This is fine, but I think it could be better.',
      high: 'Perfect! This is exactly what I was craving!',
      entry: entryDialog,
    };
  }
  
  generateLiquidClue(name: string): string {
    const clues: Record<string, string> = {
      'Lava': 'I like things that burn with intensity.',
      'Vanilla': 'I prefer simple yet timeless flavors.',
      'Cloud': 'Something light and fluffy makes me smile.',
      'Strawberry': 'I adore fruity sweetness in every sip.',
    };
    return clues[name] || 'I enjoy a refreshing drink.';
  }
  
  generateTapiocaClue(name: string): string {
    const clues: Record<string, string> = {
      'Diamond': 'Something rare and precious is my favorite.',
      'Dragon Eye': 'Mystical flavors spark my imagination.',
      'Blueberry': 'I enjoy something small, round, and full of flavor.',
      'Star': 'I love things that twinkle like the night sky.',
    };
    return clues[name] || 'I enjoy a nice chew with my drink.';
  }
}
