import { Component, inject, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
  FormBuilder,
  FormControl,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { DiceService } from './dice.service';
import { DiceDto, DiceResult } from './dice.model';
import { tap } from 'rxjs/operators';
import { UserService } from '@service/user.service';
import { PlaySoundDirective } from '@shared/directives/play-sound.directive';
import { DragSoundDirective } from '@shared/directives/drag-sound.directive';
import { AudioService } from '@shared/services/audio.service';

type DiceFormGroup = FormGroup<{
  betAmount: FormControl<number | null>;
  rollOver: FormControl<boolean>;
  targetValue: FormControl<number | null>;
}>;

@Component({
  selector: 'app-dice',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule, PlaySoundDirective, DragSoundDirective],
  templateUrl: './dice.component.html',
})
export default class DiceComponent implements OnInit {
  private readonly formBuilder = inject(FormBuilder);
  private readonly diceService = inject(DiceService);
  private readonly userService = inject(UserService);
  private readonly audioService = inject(AudioService);

  rolledValue = signal<number | null>(null);
  win = signal<boolean | null>(null);
  payout = signal<number | null>(null);
  winChance = signal(0);
  potentialWin = signal(0);

  readonly diceForm: DiceFormGroup = this.createDiceForm();

  private readonly MAX_DICE_VALUE = 100;

  ngOnInit(): void {
    this.diceForm.valueChanges
      .pipe(tap(() => this.calculateWinChanceAndPotentialWin()))
      .subscribe();

    this.calculateWinChanceAndPotentialWin();
  }

  createDiceForm(): DiceFormGroup {
    return this.formBuilder.group({
      betAmount: new FormControl<number | null>(1, {
        validators: [Validators.required, Validators.min(1)],
        nonNullable: true,
      }),
      rollOver: new FormControl<boolean>(true, {
        validators: [Validators.required],
        nonNullable: true,
      }),
      targetValue: new FormControl<number | null>(50, {
        validators: [Validators.required, Validators.min(1), Validators.max(99)],
        nonNullable: true,
      }),
    });
  }

  toggleRollMode(): void {
    const currentMode = this.diceForm.get('rollOver')?.value ?? true;
    this.diceForm.get('rollOver')?.setValue(!currentMode);
  }

  calculateWinChanceAndPotentialWin(): void {
    const formValues = this.diceForm.value;
    const target = formValues.targetValue ?? 0;
    const bet = formValues.betAmount ?? 0;
    const isOver = formValues.rollOver ?? true;

    const calculatedWinChance = isOver ? this.MAX_DICE_VALUE - target : target - 1;

    this.winChance.set(Math.max(0, calculatedWinChance));

    let multiplier = 0;
    if (calculatedWinChance > 0) {
      multiplier = (this.MAX_DICE_VALUE - 1) / calculatedWinChance;
    }

    this.potentialWin.set(bet * multiplier);
  }

  roll(): void {
    if (this.diceForm.invalid) {
      this.diceForm.markAllAsTouched();
      return;
    }

    const diceDto: DiceDto = this.diceForm.getRawValue() as DiceDto;

    this.rolledValue.set(null);
    this.win.set(null);
    this.payout.set(null);

    this.diceService.rollDice(diceDto).subscribe({
      next: (result: DiceResult) => {
        this.rolledValue.set(result.rolledValue);
        this.win.set(result.win);
        this.payout.set(result.payout);

        if (result.win) {
          this.audioService.playWinSound();
        }

        this.userService.refreshCurrentUser();
      },
      error: (error) => {
        console.error('Dice roll failed:', error);
      },
    });
  }

  setBetAmount(percentage: number): void {
    const user = this.userService['authService'].currentUserValue;
    if (!user) return;

    const balance = user.balance || 0;

    const newBet = Math.max(1, Math.floor(balance * percentage * 100) / 100);

    this.diceForm.get('betAmount')?.setValue(newBet);
    this.calculateWinChanceAndPotentialWin();
  }

  getTrackGradient(): string {
    const targetValue = this.diceForm.get('targetValue')?.value ?? 50;
    const isRollOver = this.diceForm.get('rollOver')?.value ?? true;

    if (isRollOver) {
      return `linear-gradient(to right, var(--color-accent-red) ${targetValue}%, var(--color-emerald) ${targetValue}%)`;
    } else {
      return `linear-gradient(to right, var(--color-accent-red) ${targetValue}%, var(--color-emerald) ${targetValue}%)`;
    }
  }

  hasError(controlName: string, errorName: string): boolean {
    const control = this.diceForm.get(controlName);
    return control !== null && control.touched && control.hasError(errorName);
  }
}
