import React from 'react'

import { createPortal } from 'react-dom'
import api from '~utils/api'

import Modal from '~components/Modal'
import Overlay from '~components/Overlay'
import CharacterResult from '~components/CharacterResult'
import WeaponResult from '~components/WeaponResult'
import SummonResult from '~components/SummonResult'

import './index.scss'
import PlusIcon from '~public/icons/plus.svg'

interface Props {
    close: () => void
    send: (object: Character | Weapon | Summon, position: number) => any
    grid: GridArray<Character|Weapon|Summon>
    placeholderText: string
    fromPosition: number
    object: 'weapons' | 'characters' | 'summons'
}

interface State {
    query: string,
    results: { [key: string]: any }
    loading: boolean
    message: string
    totalResults: number
}

class SearchModal extends React.Component<Props, State> {
    searchInput: React.RefObject<HTMLInputElement>

    constructor(props: Props) {
        super(props)
        this.state = {
            query: '',
            results: {},
            loading: false,
            message: '',
            totalResults: 0
        }
        this.searchInput = React.createRef<HTMLInputElement>()
    }

    componentDidMount() {
        if (this.searchInput.current) {
            this.searchInput.current.focus()
        }
    }

    filterExclusions = (o: Character | Weapon | Summon) => {
        if (this.props.grid[this.props.fromPosition] && 
            o.granblue_id == this.props.grid[this.props.fromPosition].granblue_id) {
            return null
        } else return o
    }

    fetchResults = (query: string) => {
        const excludes = Object.values(this.props.grid).filter(this.filterExclusions).map((o) => { return o.name.en }).join(',')

        api.search(this.props.object, query, excludes)
            .then((response) => {
                const data = response.data
                const totalResults = data.length
                this.setState({
                    results: data,
                    totalResults: totalResults,
                    loading: false
                })
            }, (error) => {
                this.setState({
                    loading: false,
                    message: error
                })
            })
    }

    inputChanged = (event: React.ChangeEvent<HTMLInputElement>) => {
        const query = event.target.value
        if (query.length) {
            this.setState({ query, loading: true, message: '' }, () => {
                this.fetchResults(query)
            })
        } else {
            this.setState({ query, results: {}, message: '' })
        }
    }

    sendData = (result: Character | Weapon | Summon) => {
        this.props.send(result, this.props.fromPosition)
        this.props.close()
    }

    renderSearchResults = () => {
        const { results } = this.state
         
        switch(this.props.object) {
            case 'weapons':
                return this.renderWeaponSearchResults(results)

            case 'summons':
                return this.renderSummonSearchResults(results)

            case 'characters':
                return this.renderCharacterSearchResults(results) 
        }
    }

    renderWeaponSearchResults = (results: { [key: string]: any }) => {
        return (
            <ul id="results_container">
                { results.map( (result: Weapon) => {
                    return <WeaponResult key={result.id} data={result} onClick={() => { this.sendData(result) }} />
                })}
            </ul>
        )
    }

    renderSummonSearchResults = (results: { [key: string]: any }) => {
        return (
            <ul id="results_container">
                { results.map( (result: Summon) => {
                    return <SummonResult key={result.id} data={result} onClick={() => { this.sendData(result) }} />
                })}
            </ul>
        )
    }

    renderCharacterSearchResults = (results: { [key: string]: any }) => {
        return (
            <ul id="results_container">
                { results.map( (result: Character) => {
                    return <CharacterResult key={result.id} data={result} onClick={() => { this.sendData(result) }} />
                })}
            </ul>
        )
    }

    renderEmptyState = () => {
        let string = ''

        if (this.state.query === '') {
            string = `No ${this.props.object}`
        } else {
            string = `No results found for '${this.state.query}'`
        }

        return (
            <div id="NoResults">
                <h2>{string}</h2>
            </div>
        )
    }

    render() {
        const { query, loading } = this.state

        let content: JSX.Element
        if (Object.entries(this.state.results).length == 0) {
            content = this.renderEmptyState()
        } else {
            content = this.renderSearchResults()
        }

        return (
            createPortal(
                <div>
                    <div className="ModalContainer">
                        <div className="Modal SearchModal" key="search_modal">
                            <div id="ModalTop">
                                <label className="search_label" htmlFor="search_input">
                                    <input 
                                        autoComplete="off"
                                        type="text"
                                        name="query" 
                                        className="Input" 
                                        id="search_input"
                                        ref={this.searchInput}
                                        value={query}
                                        placeholder={this.props.placeholderText}
                                        onChange={this.inputChanged}
                                    />
                                </label>
                                <PlusIcon onClick={this.props.close} />
                            </div>

                            {content}
                        </div>
                    </div>
                    <Overlay onClick={this.props.close} />
                </div>,
                document.body
            )
        )
    }
}

export default SearchModal