import express from 'express';
import socketIo from 'socket.io';
import http from 'http';
import cors from 'cors';
import mysql from 'mysql';
import dotenv from 'dotenv';
import { v1 } from 'uuid';

import { IJankenSelect, IJankenResult } from './models/message';
import { IRoom } from './models';

dotenv.config();
const port: number = 4000;
const app: express.Express = express();
const httpServer: http.Server = http.createServer(app);
const io: socketIo.Server = socketIo(httpServer);

const tournaments: Record<string, number> = {};
const players: Record<string, number> = {};
console.log(process.env.DB_ENDPOINT);
const connection = mysql.createPool({
  connectionLimit: 10,
  port: (process.env.DB_PORT ? parseInt(process.env.DB_PORT, 10) : 3306),
  host: process.env.DB_ENDPOINT,
  user: process.env.DB_USER,
  password: process.env.DB_PASS,
  database: 'catherine_league',
  charset: 'utf8mb4'
});
connection.query(
  `SELECT id, tournament_key
    FROM tournaments`,
  (error: mysql.MysqlError | null, results: any) => {
    if (error) {
      return;
    }
    if (results.length > 0) {
      results.forEach((result: any) => {
        tournaments[result.tournament_key] = result.id;
      });
    }
  }
);
connection.query(
  `SELECT id, player_key FROM players;`,
  (error: mysql.MysqlError | null, results: any) => {
    if (error) {
      console.log(error);
      return;
    }
    if (results.length > 0) {
      results.forEach((result: any) => {
        players[result.player_key] = result.id;
      });
    }
  }
);
if (process.env.NODE_ENV === 'development') {
  app.use(cors());
  app.options('*', cors());
}

app.get('/api/players/:key', (req: any, res: any) => {
  if (req.params && req.params.key && tournaments[req.params.key]) {
    const sqlToPrepare = `SELECT p.id, p.player_key, p.player_name,p.description,p.image,c.name_id, c.name, c.name_jp
    FROM players p
    JOIN player_to_tournament ptt
      on p.id = ptt.player_id
    JOIN characters c
      on c.id = p.character_id
    where ptt.tournament_id = ?`;
    const sql = mysql.format(sqlToPrepare, [tournaments[req.params.key]]);
    connection.query(sql,
      (error: mysql.MysqlError | null, results: any) => {
        if (error) {
          console.error(error);
          // players not found
        } else {
          res.send(results);
        }
      }
    );
  } else {
    // send error
  }
});
app.get('/api/players', (req: any, res: any) => {
  connection.query(
    `SELECT p.id, p.player_key, p.player_name,p.description,p.image,c.name_id, c.name, c.name_jp
      FROM players p
      JOIN characters c
        on c.id = p.character_id`,
    (error: mysql.MysqlError | null, results: any) => {
      if (error) {
        console.log(error);
        // players not found
      } else {
        res.send(results);
      }
    }
  );
});
app.get('/api/guide', (req: any, res: any) => {
  connection.query(
    `SELECT *
      FROM guide`,
    (error: mysql.MysqlError | null, results: any) => {
      if (error) {
        console.log(error);
        res.send([]);
      } else {
        res.send(results);
      }
    }
  );
});
app.get('/api/archive', (req: any, res: any) => {
  connection.query(
    `SELECT *
      FROM archive`,
    (error: mysql.MysqlError | null, results: any) => {
      if (error) {
        console.log(error);
        res.send([]);
      } else {
        res.send(results);
      }
    }
  );
});
app.get('/api/contact', (req: any, res: any) => {
  connection.query(
    `SELECT *
      FROM contact`,
    (error: mysql.MysqlError | null, results: any) => {
      if (error) {
        console.log(error);
        res.send([]);
      } else {
        res.send(results);
      }
    }
  );
});

app.use('/admin', express.static('admin'));
app.use('/players', express.static('client'));
app.use('/tournaments*', express.static('client'));
app.use('/about', express.static('client'));
app.use('/guide', express.static('client'));
app.use('/archive', express.static('client'));
app.use('/contact', express.static('client'));
app.use('/tool', express.static('tool'));
app.use(express.static('client'));

httpServer.listen(port, () => {
  console.log(`listening to port ${port}`);
});

// Janken Tool

let stages: string[] = [];
let currentIndex: number = 0;
let rooms: Record<string, IRoom> = {};
const defaultStages: string[] = ['cementery', 'prison', 'torture', 'inquisition', 'quadrangle', 'clock', 'spiral', 'empireo', 'cathedral', 'close', 'arrange'];

io.on('connection', (socket: socketIo.Socket) => {
  socket.on('disconnect', () => {
    console.log('disconnect');
  });

  socket.on('exitGame', () => {
    console.log('exitGame');
    io.emit('exitGame');
    rooms = {};
    Object.keys(io.sockets.sockets).forEach((s: string) => {
      io.sockets.sockets[s].disconnect(true);
    });
  });
  socket.on('janken', (data: IJankenSelect) => {
    console.log('janken', data);
    const currentRoom = rooms[data.room];
    if (currentRoom) {
      if (currentRoom.playerOne === data.userName) {
        currentRoom.playerOneOption = data.option;
      } else if (currentRoom.playerTwo === data.userName) {
        currentRoom.playerTwoOption = data.option;
      }
      console.log('playerOneOption', currentRoom.playerOneOption);
      console.log('playerTwoOption', currentRoom.playerTwoOption);
      if (currentRoom.playerOneOption !== '' && currentRoom.playerTwoOption !== '') {
        const message: IJankenResult = {
          playerOne: currentRoom.playerOne,
          playerOneOption: currentRoom.playerOneOption,
          playerTwo: currentRoom.playerTwo,
          playerTwoOption: currentRoom.playerTwoOption
        };
        io.to(data.room).emit('jankenResult', message);
        const sqlToPrepare = 'INSERT INTO `janken` (`match`, `result`) VALUES(?, ?);';
        const sql = mysql.format(sqlToPrepare, [data.room, JSON.stringify(message)]);
        connection.query(sql,
          (error: mysql.MysqlError | null, results: any) => {
            if (error) {
              console.error(error);
            }
          }
        );
        if (currentRoom.playerOneOption !== currentRoom.playerTwoOption) {
          delete rooms[data.room];
        }
      }
    }
  });
  socket.on('registerUser', (data: {username: string, room: string}) => {
    console.log('registerUser', data);
    let currentRoom: IRoom = {
      playerOne: '',
      playerTwo: '',
      playerOneOption: '',
      playerTwoOption: ''
    };
    if (rooms[data.room]) {
      currentRoom = rooms[data.room];
    } else {
      rooms = {
        ...rooms,
        [data.room]: currentRoom
      };
    }
    socket.join(data.room);
    if (currentRoom.playerOne === '') {
      currentRoom.playerOne = data.username;
      socket.emit('registerUser', data.username);
    } else if (currentRoom.playerTwo === '') {
      currentRoom.playerTwo = data.username;
      socket.emit('registerUser', data.username);
    }
    const message = {
      playerOne: currentRoom.playerOne,
      playerTwo: currentRoom.playerTwo
    };
    io.to(data.room).emit('login', message);
  });
  socket.on('moveToStage', () => {
    console.log('moveToStage');
    stages = shuffle(defaultStages);
    currentIndex = 0;
    io.emit('stages', stages);
  });
  socket.on('nextIndex', () => {
    console.log('nextIndex');
    if (currentIndex < stages.length) {
      currentIndex += 1;
      io.emit('updateIndex', currentIndex);
    }
  });
  socket.on('againGame', (room: string) => {
    const currentRoom = rooms[room];
    if (currentRoom) {
      console.log('againGame');
      io.to(room).emit('againGame');
      currentRoom.playerOneOption = '';
      currentRoom.playerTwoOption = '';
    }
  });
  socket.on('previousIndex', () => {
    console.log('previousIndex');
    if (currentIndex > 0) {
      currentIndex -= 1;
      io.emit('updateIndex', currentIndex);
    }
  });
  /*
  if (!room) {
    // create new room
    initRoom();
    room = true;
    const message = {
      playerOne: '',
      playerTwo: '',
    };
    socket.emit('login', message);
  } else {
    if (playerOne === '' || playerTwo === '' || playerOneOption === '' || playerTwoOption === '') {
      const message = {
        playerOne,
        playerTwo,
      };
      socket.emit('login', message);
    } else {
      const message = {
        stages,
        currentIndex
      };
      socket.emit('stages', message);
    }
  }
  */
  const initialmessage = {
    playerOne: '',
    playerTwo: '',
  };
  socket.emit('login', initialmessage);
});
const shuffle = (array: string[]): string[] => {
  return array.sort(() => Math.random() - 0.5);
};

