import React, { useState } from "react";
import "./Board.css";

const base = process.env.PUBLIC_URL;   
const assetsPath = `${base}/assets`;

const Board = ({ table, game }) => {
  const rows = [3, 4, 5, 4, 3, 2]; /* The final row of 2 is to place roads and corners */
  const [signature, setSignature] = useState("");
  const [pips, setPips] = useState(<></>);
  const [borders, setBorders] = useState(<></>);
  const [tiles, setTiles] = useState(<></>);
  const [corners, setCorners] = useState(<></>);
  const [roads, setRoads] = useState(<></>);

  const [transform, setTransform] = useState(1);

  const 
    hexRatio = 1.1547,
    tileWidth = 67,
    tileHalfWidth = tileWidth * 0.5,
    tileHeight = tileWidth * hexRatio,
    tileHalfHeight = tileHeight * 0.5,
    radius = tileHeight * 2,
    borderOffsetX = 86, /* ~1/10th border image width... hand tuned */
    borderOffsetY = 3;

  /* Actual sizing */
  const
    tileImageWidth = 90, /* Based on hand tuned and image width */
    tileImageHeight = tileImageWidth/hexRatio,
    borderImageWidth = (2 + 2/3) * tileImageWidth, /* 2.667 * .Tile.width */
    borderImageHeight = borderImageWidth * 0.29; /* 0.29 * .Border.height */

  const Tile = ({tile}) => {
    const onClick = (event) => {
      console.log(`Tile clicked: ${tile.index}`);
    };

    return <div className="Tile"
      onClick={onClick}
      data-index={tile.index}
      style={{
        top: `${tile.top}px`,
        left: `${tile.left}px`,
        width: `${tileImageWidth}px`, 
        height: `${tileImageHeight}px`,         
        backgroundImage: `url(${assetsPath}/gfx/tiles-${tile.type}.png)`,
        backgroundPositionY: `-${tile.card*tileHeight}px`
      }}
    ><div className="Tile-Shape"/></div>;
  };

  const Road = ({road}) => {
    const onClick = (event) => {
      console.log(`Road clicked: ${road.index}`);
      table.placeRoad(road.index);
    };

    return <div className="Road"
      onClick={onClick}
      data-index={road.index}
      style={{
        transform: `translate(-50%, -50%) rotate(${road.angle}deg)`,
        top: `${road.top}px`,
        left: `${road.left}px`
      }}
    ><div className="Road-Shape"/></div>;
  };
  
  const Corner = ({corner}) => {
    const onClick = (event) => {
      console.log(`Corner ${corner.index}:`, game.layout.corners[corner.index]);
      table.placeSettlement(corner.index);
      return;
    };

  return <div className="Corner"
      onClick={onClick}
      data-index={corner.index}
      style={{
        top: `${corner.top}px`,
        left: `${corner.left}px`
      }}
    ><div className="Corner-Shape"/></div>;
  };

  const Pip = ({pip}) => {
    const onClick = (event) => {
      console.log(`Pip ${pip.index}:`, game.layout.corners[pip.index]);
      table.placeRobber(pip.index);
      return;
    };

  return <div className="Pip"
      onClick={onClick}
      data-roll={pip.roll}
      data-index={pip.index}
      style={{
        top: `${pip.top}px`,
        left: `${pip.left}px`,
        backgroundImage: `url(${assetsPath}/gfx/pip-numbers.png)`,
        backgroundPositionX: `${ 100. * (pip.order % 6) / 5.}%`,
        backgroundPositionY: `${ 100 * Math.floor(pip.order / 6) / 5. }%`
      }}
    ><div className="Pip-Shape"/></div>;
  };

  const generateRoads = () => {
    let row = 0, rowCount = 0;
    let y = -2.5 + tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
      x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight;

    let index = 0;
    let road;

    const corners = [];
    
    for (let i = 0; i < 21; i++) {
      const lastRow = row === rows.length - 1;
      if (row > 2 && rowCount === 0) {
        road = {
          index: index++,
          angle: -60,
          top: y-0.5*tileHalfHeight,
          left: x-tileHalfHeight
        };
        corners.push(<Road key={`road-${index}}`} road={road}/>);
      }

      road = {
        index: index++,
        angle: 240,
        top: y,
        left: x
      };
      corners.push(<Road key={`road-${index}}`} road={road}/>);

      road = {
        index: index++,
        angle: -60,
        top: y-0.5*tileHalfHeight,
        left: x+tileHalfHeight
      };
      corners.push(<Road key={`road-${index}}`} road={road}/>);

      if (!lastRow) {
        road = {
          index: index++,
          angle: 0,
          top: y,
          left: x
        };
        corners.push(<Road key={`road-${index}}`} road={road}/>);
      }

      if (++rowCount === rows[row]) {
        if (!lastRow) {
          road = {
            index: index++,
            angle: 0,
            top: y,
            left: x+2.*tileHalfHeight
          };
          corners.push(<Road key={`road-${index}}`} road={road}/>);
        }

        if (row > 2) {
          road = {
            index: index++,
            angle: 60,
            top: y-0.5*tileHalfHeight,
            left: x+3.*tileHalfHeight
          };
          corners.push(<Road key={`road-${index}}`} road={road}/>);
        }
  
        row++;
        rowCount = 0;
        y += tileHeight - 10.5;
        x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
      } else {
        x += tileHeight;
      }
    }
    return corners;
  }
  
  const generateCorners = () => {
    let row = 0, rowCount = 0;
    let y = -8 + 0.5 * tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
      x = -tileHalfHeight -(rows[row] - 1) * 0.5 * tileHeight;
    let index = 0;
    const corners = [];
    let corner;

    for (let i = 0; i < 21; i++) {
      if (row > 2 && rowCount === 0) {
        corner = {
          index: index++,
          top: y-0.5*tileHalfHeight,
          left: x-tileHalfHeight
        };
        corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
      }

      corner = {
        index: index++,
        top: y,
        left: x
      };
      corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);

      corner = {
        index: index++,
        top: y-0.5*tileHalfHeight,
        left: x+tileHalfHeight
      };
      corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
        
      if (++rowCount === rows[row]) {
        corner = {
          index: index++,
          top: y,
          left: x+2.*tileHalfHeight
        };
        corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
         
        if (row > 2) {
          corner = {
            index: index++,
            top: y-0.5*tileHalfHeight,
            left: x+3.*tileHalfHeight
          };
          corners.push(<Corner key={`corner-${index}}`} corner={corner}/>);
        }
  
        row++;
        rowCount = 0;
        y += tileHeight - 10.5;
        x = -tileHalfHeight - (rows[row] - 1) * 0.5 * tileHeight;
      } else {
        x += tileHeight;
      }
    }
    return corners;
  }

  const generatePips = () => {
    let row = 0, rowCount = 0;
    let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
      x = -(rows[row] - 1) * 0.5 * tileHeight;
    let index = 0;
    let pip;
    return game.pipOrder.map(order => {
      pip = {
        roll: game.pips[order].roll,
        robber: index === game.robber,
        index: index++,
        top: y,
        left: x,
        order: order
      };
      const div = <Pip
        pip={pip}
        key={`pip-${order}`}
      />;
        
      if (++rowCount === rows[row]) {
        row++;
        rowCount = 0;
        y += tileWidth;
        x = - (rows[row] - 1) * 0.5 * tileHeight;
      } else {
        x += tileHeight;
      }

      return div;
    });
  };

  const generateTiles = () => {
    let row = 0, rowCount = 0;
    let y = tileHalfWidth - (rows.length - 1) * 0.5 * tileWidth,
      x = -(rows[row] - 1) * 0.5 * tileHeight;
    let index = 0;
    return game.tileOrder.map(order => {
      const tile = Object.assign({},
        game.tiles[order],
        { index: index++, left: x, top: y});

      let div = <Tile
        key={`${tile.type}-${tile.card}`}
        tile={tile}
        />;
     
      if (++rowCount === rows[row]) {
        row++;
        rowCount = 0;
        y += tileWidth;
        x = - (rows[row] - 1) * 0.5 * tileHeight;
      } else {
        x += tileHeight;
      }
    
      return div;
    });
  };

  const generateBorders = () => {
    const sides = 6;
    let side = -1;
    return game.borderOrder.map(order => {
      const border = game.borders[order];
      side++;
      let x =  + Math.sin(Math.PI - side / sides * 2. * Math.PI) * radius,
        y = Math.cos(Math.PI - side / sides * 2. * Math.PI) * radius;
      let prev = (order === 0) ? 6 : order;
      const file = `borders-${order+1}.${prev}.png`;
      return <div
        key={`border-${order}`}
        className="Border"
        border={border}
        style={{
          width: `${borderImageWidth}px`,
          height: `${borderImageHeight}px`,
          top: `${y}px`,
          left: `${x}px`,
          transform: `rotate(${side*(360/sides)}deg) translate(${borderOffsetX}px, ${borderOffsetY}px) scale(-1, -1)`,
          backgroundImage: `url(${assetsPath}/gfx/${file} )`
        }}
      />;
    });
  };

  /* If the game is loaded, and the signature is different,
   * regenerate everything */
  if (game && game.signature !== signature) {
    console.log(`Generate for ${game.signature}`);
    setPips(generatePips);
    setBorders(generateBorders);
    setTiles(generateTiles);
    setCorners(generateCorners);
    setRoads(generateRoads);
    setSignature(game.signature);
  } else {
    if (!game) {
      console.log(`No game in Board`);
    }
  }

  /* Adjust the 'transform: scale' for the BoardBox
   * so the board fills the Board 
   *
   * The board is H tall, and H * hexRatio wide */
  const board = document.querySelector('.Board');
  if (board) {
    const width = board.offsetWidth,
      height = board.offsetHeight;
    let _transform;
    if (height * hexRatio > width) {
      _transform = width / (450. * hexRatio);
    } else {
      _transform = height / (450.);
    }
    if (_transform !== transform) {
      const boardBox = board.querySelector('.BoardBox');
      if (boardBox) {
        console.log(`Setting transofrm scale to ${_transform}`);
        boardBox.style.transform = `scale(${_transform})`;
      }
      setTransform(_transform);
    }
  }

  if (game && game.turn && game.turn.roll) {
    let nodes = document.querySelectorAll('.Pip.Active');
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove('Active');
    }
    nodes = document.querySelectorAll(`.Pip[data-roll="${game.turn.roll}"]`);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.add('Active');
    }
  }

  if (game && game.placements) {
    /* Set color and type based on placement data from the server */
    game.placements.corners.forEach((corner, index) => {
      const el = document.querySelector(`.Corner[data-index="${index}"]`);
      if (!el) {
        return;
      }
      if (!corner.color) {
        el.removeAttribute('data-color');
        el.removeAttribute('data-type');
      } else {
        el.setAttribute('data-color', corner.color);
        el.setAttribute('data-type', corner.type);
      }
    });
    game.placements.roads.forEach((road, index) => {
      const el = document.querySelector(`.Road[data-index="${index}"]`);
      if (!el) {
        return;
      }
      if (!road.color) {
        el.removeAttribute('data-color');
      } else {
        el.setAttribute('data-color', road.color);
      }
    });
    /* Clear all 'Option' targets */
    let nodes = document.querySelectorAll(`.Option`);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove('Option');
    }
  
    /* Add 'Option' based on game.turn.limits */
    if (game.turn && game.turn.limits) {
      if (game.turn.limits['roads']) {
        game.turn.limits['roads'].forEach(index => {
          const el = document.querySelector(`.Road[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add('Option');
        });
      }
      if (game.turn.limits['corners']) {
        game.turn.limits['corners'].forEach(index => {
          const el = document.querySelector(`.Corner[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add('Option');
        });
      }
      if (game.turn.limits['tiles']) {
        game.turn.limits['tiles'].forEach(index => {
          const el = document.querySelector(`.Tile[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add('Option');
        });
      }
      if (game.turn.limits['pips']) {
        game.turn.limits['pips'].forEach(index => {
          const el = document.querySelector(`.Pip[data-index="${index}"]`);
          if (!el) {
            return;
          }
          el.classList.add('Option');
        });
      }
    }
  }
  
  if (game) {
    let nodes = document.querySelectorAll(`.Pip.Robber`);
    for (let i = 0; i < nodes.length; i++) {
      nodes[i].classList.remove('Robber');
    }

    if (game.robber) {
      const el = document.querySelector(`.Pip[data-index="${game.robber}"]`);
      if (el) {
        el.classList.add('Robber');
      } 
    }
  }

  const canAction = (action) => {
    return (game && game.turn && Array.isArray(game.turn.actions) && game.turn.actions.indexOf(action) !== -1);
  };

  return (
    <div className="Board">
      <div className="BoardBox">
        { borders }
        { game && <>
          <div className="Tiles" disabled>
            { tiles }
          </div>
          <div className="Pips" disabled={!canAction('place-robber') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
            { pips }
          </div>
          <div className="Corners" disabled={!canAction('place-settlement') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
            { corners }
          </div>
          <div className="Roads" disabled={!canAction('place-road') || game.turn.color !== game.color || (game.state !== 'initial-placement' && game.state !== 'normal')}>
            { roads }
          </div>
        </> }
      </div>
    </div>
  );
};

export default Board;
