import { describe, expect, it } from "vitest";
import {
  HOCKEY_GOAL_HALF_WIDTH,
  HOCKEY_HEALER_GOAL_Z,
  HOCKEY_NPC_PADDLE_Z,
  advanceHockeyHealing,
  createHockeyHealingState,
  hockeyAimPreviewVisible,
  hockeyPaddleReturnDirection,
  hockeyPuckSpeed,
  hockeyReturnDirection,
} from "./hockeyHealing";

describe("Hockey Healing", () => {
  it("starts rallies at the faster default puck speed", () => {
    expect(hockeyPuckSpeed(0)).toBe(6.2);
    expect(Math.hypot(...createHockeyHealingState(true).puckVelocity)).toBeCloseTo(6.2);
  });

  it("uses a wide goal and keeps return aim facing the NPC half", () => {
    expect(HOCKEY_GOAL_HALF_WIDTH).toBe(8);
    expect(hockeyReturnDirection([0, 0])).toEqual([0, -1]);
    expect(hockeyReturnDirection([-1, 0])[0]).toBeLessThan(0);
    expect(hockeyReturnDirection([1, 0])[0]).toBeGreaterThan(0);
    expect(hockeyReturnDirection([0, 1])[1]).toBeLessThan(0);
  });

  it("moves the enemy Pong paddle toward the puck with bounded speed", () => {
    const state = createHockeyHealingState(true);
    state.puckPosition = [7, 0];
    state.puckVelocity = [0, -5.2];

    const next = advanceHockeyHealing(state, { delta: 0.1, time: 1, playerPosition: [0, 8.5] });

    expect(next.paddleX).toBeGreaterThan(0);
    expect(next.paddleX).toBeCloseTo(1.2, 8);
  });

  it("returns an incoming puck using current left-stick aim", () => {
    const state = createHockeyHealingState(true);
    state.puckPosition = [0, 7.8];
    state.puckVelocity = [0, 5.2];
    state.aimDirection = [1, -0.5];

    const next = advanceHockeyHealing(state, { delta: 0.2, time: 3, playerPosition: [0, 8.5] });

    expect(next.returns).toBe(1);
    expect(next.puckVelocity[0]).toBeGreaterThan(0);
    expect(next.puckVelocity[1]).toBeLessThan(0);
    expect(next.lastReturnAt).toBe(3);
  });

  it("ends run when puck enters healer goal", () => {
    const state = createHockeyHealingState(true);
    state.puckPosition = [0, HOCKEY_HEALER_GOAL_Z - 0.2];
    state.puckVelocity = [0, 5.2];

    const next = advanceHockeyHealing(state, { delta: 0.1, time: 9, playerPosition: [7, 8] });

    expect(next.status).toBe("lost");
    expect(next.lostAt).toBe(9);
    expect(next.puckVelocity).toEqual([0, 0]);
  });

  it("lets the moving enemy paddle visibly return the puck", () => {
    const state = createHockeyHealingState(true);
    state.puckPosition = [0, HOCKEY_NPC_PADDLE_Z + 1];
    state.puckVelocity = [0, -5.2];

    const next = advanceHockeyHealing(state, { delta: 0.2, time: 4, playerPosition: [0, 8.5] });

    expect(next.status).toBe("live");
    expect(next.npcGoals).toBe(0);
    expect(next.paddleReturns).toBe(1);
    expect(next.paddleHitAt).toBe(4);
    expect(next.serveIndex).toBe(1);
    expect(next.puckVelocity[1]).toBeGreaterThan(0);
  });

  it("uses Pong contact position to set rebound angle", () => {
    expect(hockeyPaddleReturnDirection(-2)[0]).toBeLessThan(0);
    expect(hockeyPaddleReturnDirection(0)).toEqual([0, 1]);
    expect(hockeyPaddleReturnDirection(2)[0]).toBeGreaterThan(0);
  });

  it("shows aim preview only for nearby incoming puck", () => {
    const state = createHockeyHealingState(true);
    state.puckPosition = [0, 2];
    state.puckVelocity = [0, 5.2];
    expect(hockeyAimPreviewVisible(state, [0, 8.5])).toBe(true);
    state.puckPosition = [0, -10];
    expect(hockeyAimPreviewVisible(state, [0, 8.5])).toBe(false);
    state.puckVelocity = [0, -5.2];
    expect(hockeyAimPreviewVisible(state, [0, 8.5])).toBe(false);
  });
});
