import fs from 'fs'
import Excel from './excel'
import Draw from '../models/draw'
import MatchList from '../models/matchList'
import PlayerList from '../models/playerList'
import moment from 'moment'
import { normalize } from './helpers'
import { session } from '../index'


function initials (player) {
    const fnInitials = player.firstName
        .split('-')
        .map(element=>element
            .split(' ')
            .map(element => element[0]+'.')
            .join(' ')
        ).join('-')
    const fnInitialsDP = player.firstNameDP
        .split('-')
        .map(element=>element
            .split(' ')
            .map(element => element[0]+'.')
            .join(' ')
        ).join('-')
    return player.doubles ? `${player.name} ${fnInitials} / ${player.nameDP} ${fnInitialsDP}` : `${name} ${fnInitials}`
}

async function getDraws (req, res) {
    try {
        const draws = await Draw.find()
        return res.json(draws)
    } catch (error) {
        return res.status(400).json({ msg: error.toString() })
    }
}

async function getDraw (req, res) {
    try {
        const key = req.query.drawId ? { _id: req.query.drawId } : {}
        const draw = await MatchList.findOne(key).sort({ imported: -1 })
        return res.json(draw)
    } catch (error) {
        return res.status(400).json({ msg: error.toString() })
    }
}

async function downloadDraw (req, res) {
    try {
        const { drawId } = req.params
        
        const filename = `DisplayDraw-${drawId}-${moment().format('YYYYMMDDTHHmmss')}.xls`
        const drawFile = fs.createWriteStream(`swisstennis_files/${filename}`)
        const drawDisplay = await session.get(`https://comp.swisstennis.ch/advantage/servlet/DisplayDraw.xls?eventId=${drawId}&lang=D`, {stream: true})
        await drawDisplay.pipe(drawFile)
        const streamDone = new Promise((resolve, reject) => {
            drawFile.on('finish', resolve)
            drawFile.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 parseDraw (req,res) {
    try {
        console.log('Parsing file', req.params.filename)
        
        const filePath = `swisstennis_files/${req.params.filename}`
        const dateString = req.params.filename.match(/(\d{4}\d{2}\d{2}T\d{2}\d{2}\d{2})/)[1]
        const fileDate = moment(dateString)
        const stat = fs.statSync(filePath)
        
        const fileNewer = await Draw.find({ imported: { $gte: fileDate } })
        if (fileNewer.length) {
            throw Error('File has to be newer.')
        }
        
        console.log('About to read the draw.')
        const worksheets = await Excel.readWorkbook(`swisstennis_files/${req.params.filename}`)
        const worksheet = worksheets.Tableaux
        if (worksheet[0].length !== 1 || worksheet[1].length !== 1 || worksheet[2].length !== 1 || worksheet[3].length !== 0) {
            throw Error(`Wrong file structure.`)
        }

        const category = normalize(worksheet[2][0])
        const doubles = !!category.match(/DM.*|[MW]D.*/)
        const drawSize = ( worksheet.length - 4 + 1 ) / 2 // 4 header lines, 1 empty line between each player (n-1)
        const draw = worksheet.slice(4)
        const rounds = Math.log2(drawSize)

        const playerList = await PlayerList.findOne().sort({imported: -1}).populate('players')
        const players = playerList.players.filter(player => player.category === category)
        const matchList = await MatchList.findOne().sort({imported: -1}).populate('matches')
        const matches = matchList.matches
        
        const drawMatches = []
        for (var round = 0; round < rounds; round += 1) {
            const matchPositionOffset = Math.pow(2, round)
            const playerOffset = 2 * matchPositionOffset
            const roundOffset = playerOffset/2 - 1 
            const matchIncrement = 2 * playerOffset

            for (var seq = 0; seq < drawSize / Math.pow(2, round + 1); seq += 1) {
                const matchPosition = roundOffset + seq * matchIncrement

                // Data from spreadsheet cells
                const player1String = normalize(draw[matchPosition][round])
                const player2String = normalize(draw[matchPosition + playerOffset][round])
                const winnerString = normalize(draw[matchPositionOffset + matchPosition][round + 1])
                const timePlaceResultString = normalize(draw[matchPositionOffset + matchPosition + 1][round + 1])

                const drawPlayerRegex = /^(?:\((\d+)\))?\s*\(([RN]\d\s?(?:\d+)?|NC)\) (.+)$/
                const drawDoubleRegex = /^(?:\((\d+)\))?\s*\(([RN]\d\s?(?:\d+)?|NC)\/([RN]\d\s?(?:\d+)?|NC)\) ([^\/]+)\s*\/\s*([^\/]+)$/
                
                const player1Match = doubles ? player1String.match(drawDoubleRegex) : player1String.match(drawDoubleRegex)
                const player2Match = doubles ? player2String.match(drawDoubleRegex) : player2String.match(drawDoubleRegex)
                
                console.log(player1Match, player2Match)
                const player1 = (round === 0) ? 
                    players.find(player => player1Match && (category === player.category) && (player1Match[3] === player.fullName)) : 
                    players.find(player => (category === player.category) && (player1String === initials(player)))
                
                const player2 = (round === 0) ? 
                    players.find(player => player2Match && (category === player.category) && (player2Match[3] === player.fullName)) : 
                    players.find(player => (category === player.category) && (player2String === initials(player)))
                    
                const timePlace = timePlaceResultString.match(/^(\d{2}\/\d{2}\/\d{2})?\s+(\d{2}:\d{2})?\s*\(([^\)]+)\)?$/)
                const result = normalize(draw[matchPosition + playerOffset/2 + 1][round + 1]).match(/^((?:WO)?\s*(?:\d+\/\d+\s*)*)$/)
                const winner = winnerString
                const idString = (player1 && player2)
                const match = {
                    created: new Date(),
                    idString: '',
                    category,
                    place: timePlace && timePlace[3] || null,
                    date: timePlace && timePlace[1] && timePlace[2] && moment(`${timePlace[1]} ${timePlace[2]}`, 'DD/MM/YY HH:mm') || null,
                    round: round + 1,
                    player1: player1 && player1._id || null,
                    player2: player2 && player2._id || null,
                    winner: winner || null,
                    result: result && result[0] || null,
                    doubles
                }
                drawMatches.push(match)
            }
        }
        console.log('matches:', drawMatches.length)
        return res.json({ drawMatches })
    } catch (error) {
        res.status(400).json({ msg: error.toString() })
    }
}

async function deleteDraw (req, res) {
    try {
        const { drawId } = req.params
        
        if (!drawId) {
            throw Error('No drawId given.')
        }
        const draw = await MatchList.findOne({ _id: drawId })
        if (!draw) {
            throw Error('Draw not found.')
        }
        draw.remove()
        return res.json({ _id: drawId })
    } catch (error) {
        return res.status(400).json({ msg: error.toString() })
    }
}

export default { getDraws, getDraw, downloadDraw, parseDraw, deleteDraw }