import Phaser from 'phaser';
import { Difficulty } from '../game/types';
import { GameSceneData, loadAudioPreferences } from '../game/preferences';
import { checkForUpdate, isDismissed, dismissUpdate, CURRENT_BUILD, UpdateInfo } from '../game/update-check';

type MenuButtonPalette = {
  base: number;
  hover: number;
};

type DifficultyOption = {
  label: string;
  subtitle: string;
  value: Difficulty;
  palette: MenuButtonPalette;
};

type RuleSection = {
  heading: string;
  lines: string[];
};

type PanelBounds = {
  x: number;
  y: number;
  width: number;
  height: number;
  centerX: number;
  centerY: number;
  right: number;
  bottom: number;
};

type DecorativeCardLayout = {
  x: number;
  y: number;
  angle: number;
  scale: number;
  alpha: number;
};

type MenuLayout = {
  frameInset: number;
  isCompactViewport: boolean;
  cameraZoom: number;
  visibleBounds: PanelBounds;
  titleX: number;
  titleY: number;
  titleFontSize: number;
  subtitleY: number;
  subtitleFontSize: number;
  subtitleWrapWidth: number;
  panelPaddingX: number;
  panelPaddingY: number;
  panelTitleFontSize: number;
  rulesHeadingFontSize: number;
  rulesBodyFontSize: number;
  rulesLineSpacing: number;
  rulesLineGap: number;
  rulesSectionGap: number;
  rulesWrapWidth: number;
  footerFontSize: number;
  controlIntroFontSize: number;
  controlIntroWrapWidth: number;
  buttonWidth: number;
  buttonHeight: number;
  buttonGap: number;
  buttonTextWrapWidth: number;
  buttonLabelFontSize: number;
  buttonSubtitleFontSize: number;
  buttonLabelOffset: number;
  buttonSubtitleOffset: number;
  showButtonSubtitle: boolean;
  rulesPanel: PanelBounds;
  controlPanel: PanelBounds;
  decorativeCards: DecorativeCardLayout[];
};

const TITLE_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
  fontFamily: 'Georgia, serif',
  fontSize: '52px',
  color: '#ffd700',
  stroke: '#000000',
  strokeThickness: 4,
  resolution: 2,
};

const PANEL_TITLE_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
  fontFamily: 'Georgia, serif',
  fontSize: '24px',
  color: '#ffd700',
  resolution: 2,
};

const BODY_STYLE: Phaser.Types.GameObjects.Text.TextStyle = {
  fontFamily: 'Georgia, serif',
  fontSize: '18px',
  color: '#f8f5e6',
  resolution: 2,
};

export class MenuScene extends Phaser.Scene {
  constructor() {
    super({ key: 'MenuScene' });
  }

  create(): void {
    const width = this.scale.width;
    const height = this.scale.height;
    const audioPreferences = loadAudioPreferences();
    const layout = this.createLayout(width, height);

    this.cameras.main.setZoom(layout.cameraZoom);
    this.cameras.main.centerOn(width / 2, height / 2);

    this.drawBackground(width, height, layout);
    this.drawDecorativeCards(layout);

    this.add.text(layout.titleX, layout.titleY, 'Scopone Scientifico', {
      ...TITLE_STYLE,
      fontSize: `${layout.titleFontSize}px`,
    }).setOrigin(0.5);

    if (!layout.isCompactViewport) {
      this.add.text(layout.titleX, layout.subtitleY, 'Due squadre da due, una mano intera e lettura del tavolo fino all’ultimo punto.', {
        fontFamily: 'Georgia, serif',
        fontSize: `${layout.subtitleFontSize}px`,
        color: '#d9f2d2',
        resolution: 2,
        align: 'center',
        wordWrap: { width: layout.subtitleWrapWidth },
      }).setOrigin(0.5, 0);
    }

    this.createRulesPanel(layout);
    this.createControlPanel(layout, audioPreferences);

    // Fire-and-forget update check — shows a dismissible banner if a newer
    // CI build is available on Gitea.
    checkForUpdate(CURRENT_BUILD).then(info => {
      if (info && !isDismissed(info.buildNumber) && this.scene.isActive()) {
        this.showUpdateBanner(layout, info);
      }
    }).catch(() => { /* network unavailable — silent */ });
  }

  private createLayout(width: number, height: number): MenuLayout {
    const viewportWidth = this.scale.parentSize.width || width;
    const viewportHeight = this.scale.parentSize.height || height;
    const displayWidth = this.scale.displaySize.width || width;
    const displayHeight = this.scale.displaySize.height || height;
    const viewportAspect = viewportWidth / Math.max(viewportHeight, 1);
    const displayScale = Math.min(displayWidth / width, displayHeight / height);
    const isCompactViewport = viewportWidth <= 720 || viewportAspect < 1;
    const cameraZoom = isCompactViewport
      ? Phaser.Math.Clamp(0.43 / Math.max(displayScale, 0.001), 1.38, 1.46)
      : 1;
    const visibleBounds = this.createPanelBounds(
      (width - width / cameraZoom) / 2,
      (height - height / cameraZoom) / 2,
      width / cameraZoom,
      height / cameraZoom,
    );

    if (isCompactViewport) {
      const frameInset = 22;
      const panelGap = 12;
      const panelPaddingX = 18;
      const panelPaddingY = 14;
      const contentWidth = visibleBounds.width - frameInset * 2;
      const contentTop = visibleBounds.y + 74;
      const contentBottom = visibleBounds.bottom - 14;
      const contentHeight = contentBottom - contentTop;
      const rulesHeight = Math.round(contentHeight * 0.25);
      const controlHeight = contentHeight - rulesHeight - panelGap;
      const rulesPanel = this.createPanelBounds(
        visibleBounds.x + frameInset,
        contentTop,
        contentWidth,
        rulesHeight,
      );
      const controlPanel = this.createPanelBounds(
        visibleBounds.x + frameInset,
        rulesPanel.bottom + panelGap,
        contentWidth,
        controlHeight,
      );

      return {
        frameInset,
        isCompactViewport,
        cameraZoom,
        visibleBounds,
        titleX: width / 2,
        titleY: visibleBounds.y + 28,
        titleFontSize: 34,
        subtitleY: visibleBounds.y + 56,
        subtitleFontSize: 18,
        subtitleWrapWidth: contentWidth - 32,
        panelPaddingX,
        panelPaddingY,
        panelTitleFontSize: 19,
        rulesHeadingFontSize: 14,
        rulesBodyFontSize: 15,
        rulesLineSpacing: 2,
        rulesLineGap: 6,
        rulesSectionGap: 8,
        rulesWrapWidth: rulesPanel.width - panelPaddingX * 2,
        footerFontSize: 12,
        controlIntroFontSize: 13,
        controlIntroWrapWidth: controlPanel.width - panelPaddingX * 2,
        buttonWidth: controlPanel.width - panelPaddingX * 2,
        buttonHeight: 38,
        buttonGap: 6,
        buttonTextWrapWidth: controlPanel.width - panelPaddingX * 2 - 24,
        buttonLabelFontSize: 20,
        buttonSubtitleFontSize: 12,
        buttonLabelOffset: 0,
        buttonSubtitleOffset: 0,
        showButtonSubtitle: false,
        rulesPanel,
        controlPanel,
        decorativeCards: [],
      };
    }

    const frameInset = 34;
    const panelGap = 34;
    const contentTop = 186;
    const contentBottom = height - 48;
    const contentHeight = contentBottom - contentTop;
    const contentWidth = width - frameInset * 2;
    const rulesWidth = Math.round(contentWidth * 0.57);
    const controlWidth = contentWidth - rulesWidth - panelGap;
    const panelPaddingX = 34;
    const panelPaddingY = 28;
    const rulesPanel = this.createPanelBounds(frameInset, contentTop, rulesWidth, contentHeight);
    const controlPanel = this.createPanelBounds(rulesPanel.right + panelGap, contentTop, controlWidth, contentHeight);

    return {
      frameInset,
      isCompactViewport,
      cameraZoom,
      visibleBounds,
      titleX: width / 2,
      titleY: 82,
      titleFontSize: 52,
      subtitleY: 124,
      subtitleFontSize: 21,
      subtitleWrapWidth: width * 0.46,
      panelPaddingX,
      panelPaddingY,
      panelTitleFontSize: 24,
      rulesHeadingFontSize: 20,
      rulesBodyFontSize: 17,
      rulesLineSpacing: 5,
      rulesLineGap: 12,
      rulesSectionGap: 18,
      rulesWrapWidth: rulesPanel.width - panelPaddingX * 2,
      footerFontSize: 16,
      controlIntroFontSize: 16,
      controlIntroWrapWidth: controlPanel.width - panelPaddingX * 2,
      buttonWidth: controlPanel.width - panelPaddingX * 2,
      buttonHeight: 66,
      buttonGap: 18,
      buttonTextWrapWidth: controlPanel.width - panelPaddingX * 2 - 28,
      buttonLabelFontSize: 22,
      buttonSubtitleFontSize: 13,
      buttonLabelOffset: -10,
      buttonSubtitleOffset: 15,
      showButtonSubtitle: true,
      rulesPanel,
      controlPanel,
      decorativeCards: [
        {
          x: frameInset + 70,
          y: 104,
          angle: -18,
          scale: 0.072,
          alpha: 0.72,
        },
        {
          x: frameInset + 132,
          y: 136,
          angle: -6,
          scale: 0.069,
          alpha: 0.64,
        },
        {
          x: width - frameInset - 70,
          y: 104,
          angle: 18,
          scale: 0.072,
          alpha: 0.72,
        },
        {
          x: width - frameInset - 132,
          y: 136,
          angle: 6,
          scale: 0.069,
          alpha: 0.64,
        },
      ],
    };
  }

  private createPanelBounds(x: number, y: number, width: number, height: number): PanelBounds {
    return {
      x,
      y,
      width,
      height,
      centerX: x + width / 2,
      centerY: y + height / 2,
      right: x + width,
      bottom: y + height,
    };
  }

  private drawBackground(width: number, height: number, layout: MenuLayout): void {
    this.add.rectangle(0, 0, width, height, 0x123d22).setOrigin(0);
    this.add.rectangle(
      layout.visibleBounds.centerX,
      layout.visibleBounds.centerY,
      layout.visibleBounds.width - layout.frameInset * 2,
      layout.visibleBounds.height - layout.frameInset * 2,
      0x0b2916,
      0.28,
    )
      .setStrokeStyle(2, 0xe8c25d, 0.35);

    this.add.rectangle(
      layout.rulesPanel.centerX,
      layout.rulesPanel.centerY,
      layout.rulesPanel.width,
      layout.rulesPanel.height,
      0x0d2215,
      0.84,
    )
      .setStrokeStyle(2, 0xc8a445, 0.4);

    this.add.rectangle(
      layout.controlPanel.centerX,
      layout.controlPanel.centerY,
      layout.controlPanel.width,
      layout.controlPanel.height,
      0x10261b,
      0.88,
    )
      .setStrokeStyle(2, 0xc8a445, 0.4);
  }

  private drawDecorativeCards(layout: MenuLayout): void {
    layout.decorativeCards.forEach((card) => {
      this.add.image(card.x, card.y, 'retro').setScale(card.scale).setAngle(card.angle).setAlpha(card.alpha);
    });
  }

  private createRulesPanel(layout: MenuLayout): void {
    const panelX = layout.rulesPanel.x + layout.panelPaddingX;
    const panelY = layout.rulesPanel.y + layout.panelPaddingY;
    const sections: RuleSection[] = layout.isCompactViewport
      ? []
      : [
          {
            heading: 'Tavolo e squadre',
            lines: [
              'Si gioca in coppia: Sud e Nord contro Ovest ed Est.',
              'Nel vero scopone si distribuiscono tutte le 40 carte, 10 a giocatore.',
            ],
          },
          {
            heading: 'Come si prende',
            lines: [
              'Ogni carta cattura una carta dello stesso valore oppure una combinazione equivalente.',
              'Se sul tavolo c’è una presa diretta dello stesso valore, quella ha sempre la precedenza.',
            ],
          },
          {
            heading: 'Punteggio partita',
            lines: [
              'A fine mano contano carte, denari, settebello, primiera e scope.',
              'La sfida prosegue mano dopo mano finché una squadra arriva ad almeno 11 punti.',
            ],
          },
        ];

    this.add.text(panelX, panelY, layout.isCompactViewport ? 'Regole rapide' : 'Regolamento essenziale', {
      ...PANEL_TITLE_STYLE,
      fontSize: `${layout.panelTitleFontSize}px`,
    }).setOrigin(0, 0);

    let currentY = panelY + layout.panelTitleFontSize + (layout.isCompactViewport ? 10 : 18);

    if (layout.isCompactViewport) {
      const summaryLines = [
        '• Sud e Nord contro Ovest ed Est, con 10 carte per giocatore.',
        '• Prendi lo stesso valore o una somma: la presa diretta viene prima.',
        '• Carte, denari, settebello, primiera e scope: vince chi tocca 11 punti.',
      ];

      summaryLines.forEach((line) => {
        const ruleText = this.add.text(panelX, currentY, line, {
          ...BODY_STYLE,
          fontSize: `${layout.rulesBodyFontSize}px`,
          wordWrap: { width: layout.rulesWrapWidth },
          lineSpacing: layout.rulesLineSpacing,
        }).setOrigin(0, 0);
        currentY += ruleText.height + layout.rulesLineGap;
      });
    }

    sections.forEach((section) => {
      const sectionTitle = this.add.text(panelX, currentY, section.heading, {
        fontFamily: 'Georgia, serif',
        fontSize: `${layout.rulesHeadingFontSize}px`,
        color: '#ffffff',
        resolution: 2,
      }).setOrigin(0, 0);
      currentY += sectionTitle.height + (layout.isCompactViewport ? 6 : 10);

      section.lines.forEach((line) => {
        const ruleText = this.add.text(panelX, currentY, `• ${line}`, {
          ...BODY_STYLE,
          fontSize: `${layout.rulesBodyFontSize}px`,
          wordWrap: { width: layout.rulesWrapWidth },
          lineSpacing: layout.rulesLineSpacing,
        }).setOrigin(0, 0);
        currentY += ruleText.height + layout.rulesLineGap;
      });

      currentY += layout.rulesSectionGap;
    });

    this.add.text(panelX, layout.rulesPanel.bottom - layout.panelPaddingY - 4, layout.isCompactViewport
      ? 'Le preferenze audio salvate si applicano appena inizi.'
      : 'Scegli la difficoltà quando vuoi iniziare: le preferenze audio vengono lette al momento della partita.', {
      ...BODY_STYLE,
      fontSize: `${layout.footerFontSize}px`,
      color: '#cfe5cd',
      wordWrap: { width: layout.rulesWrapWidth },
      lineSpacing: layout.rulesLineSpacing,
    }).setOrigin(0, 1);
  }

  private createControlPanel(layout: MenuLayout, audioPreferences: ReturnType<typeof loadAudioPreferences>): void {
    const panelCenterX = layout.controlPanel.centerX;
    const difficultyOptions: DifficultyOption[] = [
      {
        label: 'Principiante',
        subtitle: 'AI prudente e leggibile',
        value: 'beginner',
        palette: { base: 0x2e7d32, hover: 0x43a047 },
      },
      {
        label: 'Avanzato',
        subtitle: 'Pressione costante sul tavolo',
        value: 'advanced',
        palette: { base: 0xd97706, hover: 0xf59e0b },
      },
      {
        label: 'Maestro',
        subtitle: 'Massima lettura e priorità alle prese forti',
        value: 'master',
        palette: { base: 0xb91c1c, hover: 0xdc2626 },
      },
    ];

    const panelTop = layout.controlPanel.y + layout.panelPaddingY;
    this.add.text(panelCenterX, panelTop, layout.isCompactViewport ? 'Gioca subito' : 'Inizia una partita', {
      ...PANEL_TITLE_STYLE,
      fontSize: `${layout.panelTitleFontSize}px`,
    }).setOrigin(0.5, 0);

    const introText = layout.isCompactViewport
      ? null
      : this.add.text(panelCenterX, panelTop + layout.panelTitleFontSize + 14, 'Ogni partita usa la difficoltà scelta qui sotto e le preferenze audio salvate.', {
          ...BODY_STYLE,
          fontSize: `${layout.controlIntroFontSize}px`,
          color: '#d7ead1',
          align: 'center',
          wordWrap: { width: layout.controlIntroWrapWidth },
        }).setOrigin(0.5, 0);

    const settingsButtonCenterY = layout.controlPanel.bottom - layout.panelPaddingY - layout.buttonHeight / 2;
    const audioStatusY = settingsButtonCenterY - layout.buttonHeight / 2 - (layout.isCompactViewport ? 12 : 24);
    const difficultyAreaTop = layout.isCompactViewport
      ? panelTop + layout.panelTitleFontSize + 10
      : introText!.y + introText!.height + 28;
    const difficultyAreaBottom = audioStatusY - (layout.isCompactViewport ? 18 : 34);
    const maxButtonHeight = (difficultyAreaBottom - difficultyAreaTop - layout.buttonGap * (difficultyOptions.length - 1)) / difficultyOptions.length;
    const buttonHeight = Math.min(layout.buttonHeight, maxButtonHeight);
    const buttonGap = difficultyOptions.length > 1
      ? (difficultyAreaBottom - difficultyAreaTop - buttonHeight * difficultyOptions.length) / (difficultyOptions.length - 1)
      : 0;

    difficultyOptions.forEach((option, index) => {
      const y = difficultyAreaTop + buttonHeight / 2 + index * (buttonHeight + buttonGap);
      this.createButton(panelCenterX, y, layout.buttonWidth, buttonHeight, option.label, layout.showButtonSubtitle ? option.subtitle : null, option.palette, layout, () => {
        this.startGame(option.value);
      });
    });

    const musicLabel = audioPreferences.musicEnabled ? 'attiva' : 'disattivata';
    const effectsLabel = audioPreferences.effectsEnabled ? 'attivi' : 'disattivati';

    this.add.text(panelCenterX, audioStatusY, `Musica ${musicLabel} · Effetti ${effectsLabel}`, {
      ...BODY_STYLE,
      fontSize: `${layout.footerFontSize}px`,
      color: '#cfe5cd',
      align: 'center',
      wordWrap: { width: layout.controlIntroWrapWidth },
    }).setOrigin(0.5);

    this.createButton(
      panelCenterX,
      settingsButtonCenterY,
      layout.buttonWidth,
      layout.buttonHeight,
      'Impostazioni audio',
      layout.showButtonSubtitle ? 'Modifica musica ed effetti in modo indipendente' : null,
      { base: 0x1f6f78, hover: 0x2f8f99 },
      layout,
      () => {
        this.openSettings();
      },
    );
  }

  private createButton(
    x: number,
    y: number,
    width: number,
    height: number,
    label: string,
    subtitle: string | null,
    palette: MenuButtonPalette,
    layout: MenuLayout,
    onClick: () => void,
  ): void {
    const background = this.add.rectangle(x, y, width, height, palette.base, 1)
      .setStrokeStyle(2, 0xf5e1a4, 0.4)
      .setInteractive({ useHandCursor: true });

    this.add.text(x, y + layout.buttonLabelOffset, label, {
      fontFamily: 'Georgia, serif',
      fontSize: `${layout.buttonLabelFontSize}px`,
      color: '#ffffff',
      stroke: '#000000',
      strokeThickness: 2,
      resolution: 2,
    }).setOrigin(0.5);

    if (subtitle) {
      this.add.text(x, y + layout.buttonSubtitleOffset, subtitle, {
        fontFamily: 'Georgia, serif',
        fontSize: `${layout.buttonSubtitleFontSize}px`,
        color: '#f7f1d5',
        resolution: 2,
        align: 'center',
        wordWrap: { width: layout.buttonTextWrapWidth },
      }).setOrigin(0.5);
    }

    background.on('pointerover', () => background.setFillStyle(palette.hover));
    background.on('pointerout', () => background.setFillStyle(palette.base));
    background.on('pointerdown', onClick);
  }

  private startGame(difficulty: Difficulty): void {
    const gameData: GameSceneData = {
      difficulty,
      audioPreferences: loadAudioPreferences(),
    };

    this.cameras.main.fadeOut(300, 0, 30, 0);
    this.cameras.main.once('camerafadeoutcomplete', () => {
      this.scene.start('GameScene', gameData);
    });
  }

  private openSettings(): void {
    this.cameras.main.fadeOut(250, 0, 30, 0);
    this.cameras.main.once('camerafadeoutcomplete', () => {
      this.scene.start('SettingsScene', { returnSceneKey: 'MenuScene' });
    });
  }

  /**
   * Renders a slim dismissible notification bar at the bottom of the visible
   * area when a newer CI build is available on Gitea.
   *
   * Layout: [  "Aggiornamento disponibile — build N"  |  Scarica →  |  ✕  ]
   */
  private showUpdateBanner(layout: MenuLayout, info: UpdateInfo): void {
    const bannerH = layout.isCompactViewport ? 40 : 48;
    const bannerW = layout.visibleBounds.width - layout.frameInset * 2;
    const cx = layout.visibleBounds.centerX;
    // Float the banner along the very bottom edge of the visible area.
    const cy = layout.visibleBounds.bottom - bannerH / 2 - 4;
    const fs = layout.isCompactViewport ? 13 : 15;
    const depth = 200;

    // Collect all objects so the dismiss handler can destroy them together.
    const objs: Phaser.GameObjects.GameObject[] = [];
    const track = <T extends Phaser.GameObjects.GameObject>(o: T): T => {
      objs.push(o); return o;
    };

    track(
      this.add.rectangle(cx, cy, bannerW, bannerH, 0x0a1e3a, 0.96)
        .setStrokeStyle(1, 0x4a90d9, 0.85)
        .setDepth(depth),
    );

    track(
      this.add.text(cx - bannerW / 2 + 12, cy,
        `Aggiornamento disponibile — build ${info.buildNumber}`,
        { fontFamily: 'Georgia, serif', fontSize: `${fs}px`, color: '#b8d8f8', resolution: 2 },
      ).setOrigin(0, 0.5).setDepth(depth + 1),
    );

    // Dismiss (✕) — always present, rightmost.
    const dismissBtn = track(
      this.add.text(cx + bannerW / 2 - 12, cy, '✕', {
        fontFamily: 'Georgia, serif', fontSize: `${fs + 4}px`, color: '#7a8a9a', resolution: 2,
      }).setOrigin(1, 0.5).setDepth(depth + 1).setInteractive({ useHandCursor: true }),
    ) as Phaser.GameObjects.Text;
    dismissBtn.on('pointerover', () => dismissBtn.setColor('#c0d0e0'));
    dismissBtn.on('pointerout', () => dismissBtn.setColor('#7a8a9a'));
    dismissBtn.on('pointerdown', () => {
      dismissUpdate(info.buildNumber);
      objs.forEach(o => o.destroy());
    });

    // "Scarica →" link — present when a direct APK URL is available.
    if (info.apkUrl) {
      const dlBtn = track(
        this.add.text(cx + bannerW / 2 - 38, cy, 'Scarica →', {
          fontFamily: 'Georgia, serif', fontSize: `${fs}px`, color: '#5ba3e8', resolution: 2,
        }).setOrigin(1, 0.5).setDepth(depth + 1).setInteractive({ useHandCursor: true }),
      ) as Phaser.GameObjects.Text;
      dlBtn.on('pointerover', () => dlBtn.setColor('#90c8ff'));
      dlBtn.on('pointerout', () => dlBtn.setColor('#5ba3e8'));
      dlBtn.on('pointerdown', () => window.open(info.apkUrl!, '_blank'));
    }
  }
}
