import fs from 'fs'
import Excel from './excel'
import Player from '../models/player'
import Match from '../models/match'
import MatchList from '../models/matchList'
import moment from 'moment'
import { normalize } from './helpers'
import { session } from '../index'
import { configDb } from '../../api'

async function getCalendars(req, res) {
  try {
    // Calendar list from database. Unly query certain fields.
    const calendars = await MatchList.find().select({
      _id: 1,
      imported: 1,
      file: 1,
      fileSize: 1,
    })
    return res.json(calendars)
  } catch (error) {
    return res.status(400).json({ msg: error.toString() })
  }
}

async function getCalendar(req, res) {
  try {
    const key = req.query.calendarId ? { _id: req.query.calendarId } : {}
    const calendar = await MatchList.findOne(key)
      .sort({ imported: -1 })
      .populate('matches')
    await Promise.all(
      calendar.matches.map(async (match) => {
        await Player.populate(match, 'player1')
        await Player.populate(match, 'player2')
      })
    )
    return res.json(calendar)
  } catch (error) {
    return res.status(400).json({ msg: error.toString() })
  }
}

async function downloadCalendar(req, res) {
  const tournament = req.query.tournament || configDb.tournamentId.value

  if (!tournament) {
    return res.json({ msg: 'No tournament given.' })
  }
  try {
    const filename = `Calendar-${tournament}-${moment().format(
      'YYYYMMDDTHHmmss'
    )}.xls`
    const calendarFile = fs.createWriteStream(`swisstennis_files/${filename}`)
    const calendar = await session.get(
      `https://comp.swisstennis.ch/advantage/servlet/Calendar.xls?Lang=D&tournament=Id${tournament}&Type=Match&Inp_DateRangeFilter.fromDate=07.07.2021&Inp_DateRangeFilter.toDate=18.07.2021`,
      { stream: true }
    )
    await calendar.pipe(calendarFile)
    const streamDone = new Promise((resolve, reject) => {
      calendarFile.on('finish', resolve)
      calendarFile.on('error', reject)
    })
    await streamDone
    const stats = fs.statSync(`swisstennis_files/${filename}`)
    return res.json({ filename, size: stats.size, mtime: stats.mtime })
  } catch (error) {
    return res.status(400).json({ msg: error.toString() })
  }
}

async function parseCalendar(req, res) {
  try {
    console.log('Parsing file', req.params.filename)

    const filePath = `swisstennis_files/${req.params.filename}`
    const dateElems = req.params.filename
      .match(/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})/)
      .slice(1, 7)
    const fileDate = new Date(
      `${dateElems[0]}-${dateElems[1]}-${dateElems[2]} ${dateElems[3]}:${dateElems[4]}:${dateElems[5]}`
    )
    const stat = fs.statSync(filePath)

    const fileNewer = await MatchList.find({ imported: { $gte: fileDate } })
    if (fileNewer && fileNewer.length) {
      throw Error('File has to be newer.')
    }

    console.log('About to read the calendar list.')
    const worksheets = await Excel.readWorkbook(
      `swisstennis_files/${req.params.filename}`
    )
    const worksheet = worksheets.Sheet1
    console.log('DEBUG: worksheet', worksheet)
    if ((worksheet[2].length < 8) | (worksheet[2].length > 9)) {
      throw Error(`Wrong file structure.`)
    }

    const allMatches = await Promise.all(
      worksheet.slice(2, worksheet.length).map(async (data, key) => {
        const fileMatch = {
          created: fileDate,
          fileLine: key,
          category: normalize(data[3]),
          place: normalize(data[0]),
          date: data[1],
          result: normalize(data[8]),
        }
        fileMatch.doubles = !!fileMatch.category.match(/DM.*|[MW]D.*/)
        const player1 = await Player.findOne({
          idString: `${fileMatch.category} % ${normalize(data[4])}`,
        }).sort({ created: -1 })
        const player2 = await Player.findOne({
          idString: `${fileMatch.category} % ${normalize(data[6])}`,
        }).sort({ created: -1 })
        fileMatch.idString = `${fileMatch.category} % ${
          player1 ? player1.idString : `${key}_1`
        } - ${player2 ? player2.idString : `${key}_2`}`
        fileMatch.player1 = player1 ? player1._id : null
        fileMatch.player2 = player2 ? player2._id : null

        const match = new Match(fileMatch)
        await match.save()
        return match._id
      })
    )
    const matchList = new MatchList({
      imported: fileDate,
      file: req.params.filename,
      fileSize: stat.size,
      matches: allMatches,
    })
    await matchList.save()

    return res.json({ matchList })
  } catch (error) {
    res.status(400).json({ msg: error.toString() })
  }
}

// Delete a calendar
async function deleteCalendar(req, res) {
  try {
    const { calendarId } = req.params

    if (!calendarId) {
      throw Error('No calendarId given.')
    }
    const calendar = await MatchList.findOne({ _id: calendarId })
    if (!calendar) {
      throw Error('Calendar not found.')
    }
    calendar.remove()
    return res.json({ _id: calendarId })
  } catch (error) {
    return res.status(400).json({ msg: error.toString() })
  }
}

export default {
  getCalendars,
  getCalendar,
  downloadCalendar,
  parseCalendar,
  deleteCalendar,
}
