import React from 'react';
import { Heading, Box, Flex, Icon, Link as CLink, Button } from '@chakra-ui/core';
import { Link, Redirect } from "react-router-dom";
import DayPicker from "react-day-picker";
import "react-day-picker/lib/style.css";

import { sources } from '../sources.json';

function addDays(date, days) {
    var result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
}

export default class Location extends React.Component {
    constructor(props) {
        super(props);
        this.state = { tides: [{ date: '', time: '', distance: 0 }],
                       waves: false,
                       weather: false,
                       locationIndex: 0,
                       loaded: false,
                       date: new Date(new Date().toLocaleDateString()),
                       id: '',
                       name: '',
                       nextTideable: '',
                       urls: { marine: '', weather: '' },
                       redirectToDay: false,
                       showDayPicker: false,
                       goodTides: [],
                       okTides: [],
                       tidesDate: new Date(2000, 1, 1)
                     };
    }

    update = () => {
        fetch(`/api/location/${this.state.id}/date/` + this.state.date.toISOString())
            .then(res => res.json())
            .then(obj => {
                const waves = obj.waves.length > 0 ? obj.waves
                      .sort((a, b) => new Date(a.date) - new Date(b.date))[0] : false;
                const highestSwell = waves ? waves.swellDetails
                      .reduce((r, x) => x.height > r.height ? x : r, { height: -1 }) :
                      false;
                const windHigher = waves ? waves.windHeight > highestSwell.height : false;
                const w = obj.weather;

                const nextTideable = new Date(obj.nextTideable.date);

                this.setState({ tides: obj.tides,
                                waves: waves ?
                                { height: windHigher ? waves.windHeight : highestSwell.height,
                                  direction: windHigher ? '' : highestSwell.direction,
                                  swell: obj.waves.map(w => w.swellText),
                                  wind: obj.waves.map(w => w.windText)
                                } : false,
                                weather: w ?
                                { wind: { speed: w.windSpeed,
                                          direction: w.windDirection },
                                  conditions: w.shortForecast,
                                  high: w.temperature
                                } : false,
                                name: obj.name,
                                loaded: true,
                                nextTideable: nextTideable.getFullYear() + '/' +
                                (nextTideable.getMonth() + 1) + '/' +
                                nextTideable.getDate(),
                                urls: obj.urls,
                                redirectToDay: false
                              });
            });
    }

    fetchTideability = () => {
        fetch(`/api/location/${this.state.id}/tide/` + this.state.date.toISOString())
            .then(res => res.json())
            .then(obj => this.setState({
                goodTides: obj.goodTides.map(x => new Date(x))
                    .filter(x => x.getHours() < 22 && x.getHours() > 5),
                okTides: obj.okTides.map(x => new Date(x))
                    .concat(obj.goodTides.map(x => new Date(x))
                            .filter(x => x.getHours() >= 22 && x.getHours() <= 5)),
                tidesDate: this.state.date
            }));
    }

    componentDidMount() {
        const { match: { params } } = this.props;
        this.setState({ id: params.id,
                        date: params.y ? new Date(parseInt(params.y), parseInt(params.m) - 1, parseInt(params.d)) :
                        this.state.date },
                      () => {
                          this.update();
                          this.fetchTideability();
                      });
    }

    componentDidUpdate(oldProps) {
        const { match: { params } } = this.props;
        const oldParams = oldProps.match.params;
        const date = '' + params.y + params.m + params.d;
        const oldDate = '' + oldParams.y + oldParams.m + oldParams.d;
        if (params.id !== oldProps.match.params.id ||
            date !== oldDate) {
            this.setState({ id: params.id, loaded: false,
                            date: params.y ? new Date(parseInt(params.y), parseInt(params.m) - 1, parseInt(params.d)) : this.state.date
                          },
                          () => {
                              this.update();
                              // if its been a month since we fetched good/okTides
                              if (params.id !== oldProps.match.params.id ||
                                  Math.abs(this.state.date - this.state.tidesDate) >= 2588400000) {
                                  this.fetchTideability();
                              }
                          });
        }
    }

    dayClick = day => {
        this.setState({ redirectToDay: day });
    }

    toggleDayPicker = () => {
        this.setState({ showDayPicker: !this.state.showDayPicker });
    }

    render() {
        if (this.state.loaded && this.state.redirectToDay) {
            return (<Redirect to={`/location/${this.state.id}/` +
                                  this.state.redirectToDay.getFullYear() + '/' +
                                  (this.state.redirectToDay.getMonth() + 1) + '/' +
                                   this.state.redirectToDay.getDate()} />);
        } else if (this.state.loaded) {
            const sourceIndex = sources.map(source => source.id).indexOf(this.state.id);
            const prevLocationObj = sources[sourceIndex === 0 ?
                                            sources.length - 1 : sourceIndex - 1];
            const nextLocationObj = sources[sourceIndex === sources.length - 1 ?
                                            0 : sourceIndex + 1];
            const prevLocation =
                  (
                      <Link to={`/location/${prevLocationObj.id}/` +
                                this.state.date.getFullYear() + '/' +
                                (this.state.date.getMonth() + 1) + '/' +
                            this.state.date.getDate()}>
                        <Icon name='arrow-left' />
                      </Link>
                  );
            const nextLocation =
                  (
                      <Link to={`/location/${nextLocationObj.id}/` +
                                this.state.date.getFullYear() + '/' +
                                (this.state.date.getMonth() + 1) + '/' +
                            this.state.date.getDate()}>
                        <Icon name='arrow-right' />
                      </Link>
                  );
            const nextDayDate = addDays(this.state.date, 1);
            const nextDay = '/location/' + this.state.id + '/' +
                  nextDayDate.getFullYear() + '/' +
                  (nextDayDate.getMonth() + 1) + '/' +
                  nextDayDate.getDate();
            const prevDayDate = addDays(this.state.date, -1);
            // const today = new Date(new Date().toLocaleDateString());
            const prevDay =
                  '/location/' + this.state.id + '/' +
                  prevDayDate.getFullYear() + '/' +
                  (prevDayDate.getMonth() + 1) + '/' +
                  prevDayDate.getDate();
            const { weather } = this.state;
            const tideMin = Math.min.apply(Math, this.state.tides.map(x => x.distance)),
                  tideColor = tideMin < -0.3 ? 'green' : tideMin < 0 ? 'orange' : 'black';
            const waveColor = this.state.waves.height < 5 ? 'green' :
                  this.state.waves.height < 10 ? 'orange' : 'red';
            const conditionsScore = RegExp('rain', 'g').test(weather.conditions) ? 5 : 0;
            const tempScore = weather.high >= 60 ? 0 : weather.high >= 50 ? 5 : 10;
            const windSpeed = weather.wind ? weather.wind.speed : "0";
            const maxWind = Math.max.apply(Math, windSpeed.match(/[0-9]+/g).map(x => parseInt(x)));
            const windScore = maxWind <= 10 ? 0 : maxWind <= 20 ? 5 : 10;
            const weatherScore = Math.max(conditionsScore, tempScore, windScore);
            const weatherColor = weatherScore < 5 ? 'green' : weatherScore === 5 ? 'orange' : 'red';
            return (
                <Box bg='blue.100' p={2}>
                  <Heading size='2xl' as='h1' marginBottom='0.5em'>
                    <Flex justify='space-between' align='center'>
                      <Box color='gray.400'>{prevLocation}</Box>
                      <Box color='red.800'>{this.state.name}</Box>
                      <Box color='gray.400'>{nextLocation}</Box>
                    </Flex>
                  </Heading>
                  <Heading size='m'>
                    <Flex justify='space-between' align='center' marginBottom='0.5em'>
                      <Box color='gray.400'>
                        <Link to={prevDay}><Icon name='arrow-left' /></Link>
                      </Box>
                      <Button onClick={this.toggleDayPicker}
                              variant='outline'>
                        {this.state.date.toLocaleDateString()}
                      </Button>
                      <Box color='gray.400'>
                        <Link to={nextDay}><Icon name='arrow-right' /></Link>
                      </Box>
                    </Flex>
                    {this.state.showDayPicker ? (
                        <Flex justify='center'>
                          <DayPicker month={this.state.date}
                                     selectedDays={[this.state.date]}
                                     onDayClick={this.dayClick}
                                     modifiers={{ goodtides: this.state.goodTides,
                                                  oktides: this.state.okTides }}
                                     />
                        </Flex>
                    ) : (<></>)}
                    <Flex w='100%' justify='center' marginBottom='0.5em'>
                      <Button variant='outline'>
                        <Link to={`/location/${this.state.id}/${this.state.nextTideable}`}>Next Tideable <Icon name='arrow-right' /></Link>
                      </Button>
                    </Flex>
                  </Heading>
                  <Box shadow='md' p={5} borderWidth='1px' bg='white' mb={4}>
                    <Heading as='h3' size='lg' color={tideColor + '.500'}>
                      <CLink href={this.state.urls.tide} isExternal>
                        Tide <Icon name='external-link' />
                      </CLink>
                    </Heading>
                    {this.state.tides.map((tide, i) => (
                        <Box key={i}>
                          Level: {tide.distance} ft
                          Time: {new Date(tide.date).toLocaleTimeString()}
                        </Box>
                    ))}
                </Box>
                    {this.state.waves ? (
                        <Box shadow='md' p={5} borderWidth='1px' bg='white' mb={4}>
                          <Heading as='h3' size='lg' color={waveColor + '.500'}>
                            <CLink href={this.state.urls.marine} isExternal>
                              Waves <Icon name='external-link' />
                            </CLink>
                          </Heading>
                          <Flex direction='column'>
                            <Box>
                              Max waves: {this.state.waves.height}ft {this.state.waves.direction}
                            </Box>
                          </Flex>
                        </Box>
                    ) : (<></>)}
                {this.state.weather ? (
                    <Box shadow='md' p={5} borderWidth='1px' bg='white' mb={4}>
                      <Heading as='h3' size='lg' color={weatherColor + '.500'}>
                      <CLink href={this.state.urls.weather} isExternal>
                        Weather <Icon name='external-link' />
                      </CLink>
                    </Heading>
                    <Flex direction='column'>
                      <Box>Conditions: {weather.conditions}</Box>
                      <Box>High: {weather.high}</Box>
                      <Box>Wind: {weather.wind.speed} {weather.wind.direction}</Box>
                    </Flex>
                  </Box>
                ) : (<></>)}
                </Box>
            );
        } else {
            return ('Loading...');
        }
    }
}
