import { define, createThemes } from 'forge'
import { move, nameChange, playAgain } from './actions'
import type { Game } from '../types'
import { sessionId } from 'pyre/client'

const theme = createThemes({
  light: {
    bg: '#fff',
    fg: '#333',
    fgActive: '#000',
    border: '#333',
    hoverBg: 'rgba(0, 0, 0, 0.05)',
    inputBg: '#fff',
    inputBorder: '#999',
  },
  dark: {
    bg: '#1a1a1a',
    fg: '#aaa',
    fgActive: '#fff',
    border: '#555',
    hoverBg: 'rgba(255, 255, 255, 0.1)',
    inputBg: '#333',
    inputBorder: '#666',
  },
})

const Player = define('Player', {
  display: 'flex',
  alignItems: 'center',
  gap: 12,
  padding: '12px 20px',

  parts: {
    Symbol: {
      fontSize: 32,
    },
    Indicator: {
      width: 8,
      height: 8,
      borderRadius: '50%',
      background: '#4ade80',
      opacity: 0,
      transition: 'opacity 0.2s ease',
    },
    Name: {
      base: 'span',
      fontSize: 18,
      fontWeight: 500,
      color: theme('fg'),
      padding: '2px 6px',
      borderRadius: 4,
      border: '1px solid transparent',
      outline: 'none',
      minWidth: 60,
    },
  },

  variants: {
    active: {
      parts: {
        Name: {
          color: theme('fgActive'),
        },
        Indicator: {
          opacity: 1,
        },
      },
    },
    editable: {
      parts: {
        Name: {
          cursor: 'text',
          states: {
            hover: {
              background: theme('hoverBg'),
            },
            focus: {
              border: `1px solid ${theme('inputBorder')}`,
              background: theme('inputBg'),
            },
          },
        },
      },
    },
    player: {
      o: {
        parts: {
          Symbol: {
            filter: 'sepia(1) saturate(5) hue-rotate(180deg) brightness(0.9)',
          },
        },
      },
    },
  },

  render({ props, parts: { Root, Symbol, Indicator, Name } }) {
    const onKeyDown = (e: KeyboardEvent) => {
      if (!e.target) return
      const target = (e.target as HTMLSpanElement)

      if (e.key === 'Enter') {
        e.preventDefault()
        const newName = target.textContent || `Player ${props.player.toUpperCase()}`
        nameChange(newName)
        target.blur()
      } else if (e.key === 'Escape') {
        e.preventDefault()
        target.blur()
      }
    }

    return (
      <Root>
        <Indicator />
        <Symbol>{props.symbol}</Symbol>
        <Name
          contenteditable={props.editable ? "true" : "false"}
          spellcheck="false"
          onKeyDown={props.editable ? onKeyDown : undefined}
        >
          {props.name}
        </Name>
      </Root>
    )
  },
})

const Board = define('Board', {
  display: 'inline-grid',
  gridTemplateColumns: 'repeat(3, 1fr)',
  position: 'relative',
})

const Tile = define('Tile', {
  base: 'button',
  width: 120,
  height: 120,
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  fontSize: 60,
  background: 'transparent',
  border: 'none',
  borderRight: `3px solid ${theme('border')}`,
  borderBottom: `3px solid ${theme('border')}`,
  cursor: 'pointer',
  transition: 'background 0.15s ease',

  states: {
    hover: {
      background: theme('hoverBg'),
    },
  },

  variants: {
    col: {
      last: { borderRight: 'none' },
    },
    row: {
      last: { borderBottom: 'none' },
    },
    player: {
      o: { filter: 'sepia(1) saturate(5) hue-rotate(180deg) brightness(0.9)' },
    },
  },
})

const WinLine = define('WinLine', {
  position: 'absolute',
  borderRadius: 4,

  variants: {
    direction: {
      diagonal: {
        width: '140%',
        height: 6,
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%) rotate(45deg)',
      },
      'diagonal-reverse': {
        width: '140%',
        height: 6,
        top: '50%',
        left: '50%',
        transform: 'translate(-50%, -50%) rotate(-45deg)',
      },
      horizontal: {
        width: '100%',
        height: 6,
        left: 0,
        transform: 'translateY(-50%)',
      },
      vertical: {
        width: 6,
        height: '100%',
        top: 0,
        transform: 'translateX(-50%)',
      },
    },
    position: {
      top: { top: 60 },
      middle: { top: '50%' },
      bottom: { top: 300 },
      left: { left: 60 },
      center: { left: '50%' },
      right: { left: 300 },
    },
    player: {
      x: { background: '#e74c3c' },
      o: { background: '#3498db' },
    },
  },
})

const WinBanner = define('WinBanner', {
  position: 'absolute',
  top: 24,
  left: '50%',
  transform: 'translateX(-50%)',
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  gap: 12,
  padding: '16px 32px',
  borderRadius: 12,
  background: theme('bg'),
  boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
  zIndex: 10,

  parts: {
    Title: {
      fontSize: 20,
      fontWeight: 'bold',
      color: theme('fgActive'),
    },
    Button: {
      base: 'button',
      fontSize: 14,
      fontWeight: 600,
      padding: '8px 20px',
      borderRadius: 6,
      border: 'none',
      cursor: 'pointer',
    },
  },

  variants: {
    player: {
      x: {
        parts: {
          Button: {
            background: '#e74c3c',
            color: 'white',
          },
        },
      },
      o: {
        parts: {
          Button: {
            background: '#3498db',
            color: 'white',
          },
        },
      },
    },
  },

  render({ props, parts: { Root, Title, Button } }) {
    return (
      <Root>
        <Title>{props.title}</Title>
        <Button onClick={() => window.location.href = '/'}>New Game</Button>
        <Button onClick={playAgain}>Play Again</Button>
      </Root>
    )
  },
})

const darkQuery = window.matchMedia('(prefers-color-scheme: dark)')
const getTheme = () => darkQuery.matches ? 'dark' : 'light'
let currentTheme = getTheme()

darkQuery.addEventListener('change', () => {
  currentTheme = getTheme()
  document.querySelector('[data-theme]')?.setAttribute('data-theme', currentTheme)
})

const Phone = define('Phone', {
  position: 'fixed',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
  width: 'min(100vw - 40px, (100vh - 40px) * 9 / 19.5)',
  height: 'min(100vh - 40px, (100vw - 40px) * 19.5 / 9)',
  overflow: 'hidden',

  render({ props, parts: { Root } }) {
    return <Root data-theme={currentTheme}>{props.children}</Root>
  },
})

const GameContainer = define('Game', {
  display: 'flex',
  flexDirection: 'column',
  alignItems: 'center',
  justifyContent: 'center',
  gap: 16,
  width: '100%',
  height: '100%',
})

const BoardWrapper = define('BoardWrapper', {
  position: 'relative',
})

const symbol = (tile: string): string =>
  tile === 'x' ? '❌' : tile === 'o' ? '⭕️' : ''

const PlayerO = ({ game, myPlayer }: { game: Game, myPlayer: string }) =>
  <Player symbol="⭕️" game={game} name={game.names.o} player="o" active={game.turn === 'o'} editable={myPlayer === 'o'} />

const PlayerX = ({ game, myPlayer }: { game: Game, myPlayer: string }) =>
  <Player symbol="❌" game={game} name={game.names.x} player="x" active={game.turn === 'x'} editable={myPlayer === 'x'} />

const tryMove = (game: Game, player: 'x' | 'o', x: number, y: number) => {
  return game.turn === player && game.phase === 'play' ? () => move(x, y) : () => { }
}

export default ({ game }: { game: Game }) => {
  const player = game.players[sessionId]
  if (!player) throw new Error(`no player for session: ${sessionId}`)

  const winnerName = game.winLine?.player === 'x' ? game.names.x : game.names.o

  return (
    <Phone>
      <GameContainer>
        {game.winLine && (
          <WinBanner
            title={`${winnerName} wins!`}
            player={game.winLine.player}
          />
        )}
        {player === 'x' && <PlayerO game={game} myPlayer={player} />}
        {player === 'o' && <PlayerX game={game} myPlayer={player} />}
        <BoardWrapper>
          <Board>
            <Tile onClick={tryMove(game, player, 0, 0)} player={game.board[0][0]}>{symbol(game.board[0][0])}</Tile>
            <Tile onClick={tryMove(game, player, 0, 1)} player={game.board[0][1]}>{symbol(game.board[0][1])}</Tile>
            <Tile onClick={tryMove(game, player, 0, 2)} col="last" player={game.board[0][2]}>{symbol(game.board[0][2])}</Tile>

            <Tile onClick={tryMove(game, player, 1, 0)} player={game.board[1][0]}>{symbol(game.board[1][0])}</Tile>
            <Tile onClick={tryMove(game, player, 1, 1)} player={game.board[1][1]}>{symbol(game.board[1][1])}</Tile>
            <Tile onClick={tryMove(game, player, 1, 2)} col="last" player={game.board[1][2]}>{symbol(game.board[1][2])}</Tile>

            <Tile onClick={tryMove(game, player, 2, 0)} row="last" player={game.board[2][0]}>{symbol(game.board[2][0])}</Tile>
            <Tile onClick={tryMove(game, player, 2, 1)} row="last" player={game.board[2][1]}>{symbol(game.board[2][1])}</Tile>
            <Tile onClick={tryMove(game, player, 2, 2)} row="last" col="last" player={game.board[2][2]}>{symbol(game.board[2][2])}</Tile>
          </Board>
          {game.winLine && (
            <WinLine
              direction={game.winLine.direction}
              position={game.winLine.position}
              player={game.winLine.player}
            />
          )}
        </BoardWrapper>
        {player === 'x' && <PlayerX game={game} myPlayer={player} />}
        {player === 'o' && <PlayerO game={game} myPlayer={player} />}
      </GameContainer>
    </Phone>
  )
}
