import _ from 'lodash';
import React, {Component, forwardRef, useImperativeHandle, useState, Fragment, useRef, useEffect} from 'react';
import Styled from 'styled-components/native';
import {Calendar as RNCalendar, ExpandableCalendar, AgendaList, CalendarProvider, WeekCalendar, LocaleConfig} from 'react-native-calendars';
import Left from '~/Assets/Svgs/calendar/left.svg';
import Right from '~/Assets/Svgs/calendar/right.svg';
import Theme from '~/Themes';

import {
  Platform,
  Alert,
  StyleSheet,
  View,
  Text,
  TouchableOpacity,
  Button
} from 'react-native';
import { Util } from '~/Utils/utils';

LocaleConfig.locales['ko'] = {
  monthNames: ['1월','2월','3월','4월','5월','6월','7월','8월','9월','10월','11월','12월'],
  monthNamesShort: ['1.','2.','3','4','5','6','7.','8','9.','10','11','12'],
  dayNames: ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'],
  dayNamesShort: ['일','월','화','수','목','금','토'],
  today: '오늘'
};
LocaleConfig.defaultLocale = 'ko';

const Colors = {
  DayColor: '#707070',
  DisabledDayColor: '#dedede',
  CurrentDayBackgroundColor: '#40b9ff',
  CurrentDayColor: 'white',
};
const DayContainer = Styled.TouchableOpacity`
  width:100%;
  align-items:center;
`;
const DayLabelContainer = Styled.View`
  width:30; height:30;
  border-radius:20;
  overflow:hidden;
  align-items:center; 
  justify-content:center;
`;
const DayLabel = Styled.Text`
  color: #707070;
`;
const DayPeriodContainer = Styled.View`
  width: 100%;
  height: 3;
  margin-top:1;
  margin-bottom:1;
  flex-direction:row;
  align-items:center;
  justify-content:center;
`;
const Space = Styled.View`
  flex:0.1;
  height:100%;
`;
const Empty = Styled.View`
  flex:1;
  height:100%;
`;
const DayEnd = Styled.View`
  background-color:red;
  flex:1;
  height:100%;
  border-top-right-radius: 2.5;
  border-bottom-right-radius: 2.5;
  overflow:hidden;
`;
const DayStart = Styled.View`
  background-color:blue;
  flex:1;
  height:100%;
  border-top-left-radius: 2.5;
  border-bottom-left-radius: 2.5;
  overflow:hidden;
`;
const DayPeriod = Styled.View`
  flex:1;
  background-color:blue;
  height:100%;
`;
const DayDot = Styled.View`
  width:82%;
  height:3;
  border-radius:2;
  background-color:blue;
  overflow:hidden;
`;
const AgendaBar = Styled.TouchableOpacity`
  width:100%;
  height:20;
  background-color:white;
  border: 0px solid #f5f5f5;
  border-bottom-width: 1px;
  align-items: center;
  justify-content: center;
`;
const AgendaClose = Styled.View`
  width: 44;
  height: 8;
  background-color: #f5f5f5;
  border-radius: 5;
  overflow:hidden;
`;
const AgendaContainer = Styled.View`
  width:100%;
  height:100%;
  max-height:100%;
`;
const DayComponent = (props) => {
  const { state, marking, date, onPress, dataTypes } = props;
  return (
    <DayContainer onPress={() => { onPress(date); }}>
      {marking && marking.current ? (
        <DayLabelContainer style={[{backgroundColor:Colors.CurrentDayBackgroundColor}]}>
          <DayLabel style={{color: Colors.CurrentDayColor}}>{date.day}</DayLabel>
        </DayLabelContainer>
      ) : (
        <DayLabelContainer>
          <DayLabel style={{color: state==='disabled'?Colors.DisabledDayColor:Colors.DayColor}}>{date.day}</DayLabel>
        </DayLabelContainer>
      )}
      {dataTypes.map((type, index) => {
        const periods = marking && marking.periods;
        let item = null;
        if(periods) {
          item = periods.find(val => val.type == type.type);
        }
        const color = type.color;
        return (
          <DayPeriodContainer key={index}>
            {(() => {
              if(!item) {
                return <Empty />
              } else if(item.start && item.end) {
                return <DayDot style={[{backgroundColor:color}]} />
              } else if(item.start && !item.end) {
                return <Fragment><Space /><DayStart style={[{backgroundColor:color}]} /></Fragment>
              } else if(!item.start && item.end) {
                return <Fragment><DayEnd style={[{backgroundColor:color}]} /><Space /></Fragment>
              } else {
                return <DayPeriod style={[{backgroundColor:color}]} />
              }
            })()}
          </DayPeriodContainer>
        )
      })}
    </DayContainer>
  )
}

export const GetGroupingDate = (data, startDateKey='StartDate', endDateKey='EndDate', groupKey='WorkTypeName') => {
  let list = [];
  let grouping = false;
  for(let item of data) {
    const found = list.find(value => value[groupKey] == item[groupKey] 
        && value[endDateKey] >= item[startDateKey] 
        && value[startDateKey] <= item[endDateKey]);

    if(found) {
      if(found[startDateKey] > item[startDateKey]) found[startDateKey] = item[startDateKey];
      if(found[endDateKey] < item[endDateKey]) found[endDateKey] = item[endDateKey];
      grouping = true;
    } else {
      list.push(item);
    }
  }

  if(grouping) {
    return GetGroupingDate(list, startDateKey, endDateKey, groupKey);
  } else {
    return list;
  }
}

export const ToMarkedDates = (data, startDateKey='StartDate', endDateKey='EndDate', typeKey='WorkTypeName') => {
  if(Array.isArray(data)) {
    const now = Util.toDateString();
    const sorted = data.sort((a,b) => a[startDateKey] - b[startDateKey]);
    let marked = {};

    const addMarked = (dateString, start, end, type) => {
      if(typeof marked[dateString] === 'undefined') {
        marked[dateString] = {
          periods:[{start:start, end:end, type:type}],
          current: (dateString == now)
        };
      } else {
        marked[dateString].periods.push({start:start, end:end, type:type});
      }
    }

    for(let item of sorted) {
      const start = new Date(item[startDateKey]);
      const end = new Date(item[endDateKey]);

      let curr = new Date(start);
      if(start < end) {
        while(curr < end) {
          addMarked(Util.toDateString(curr), (curr.getTime() == start.getTime() ? true : false), false, item[typeKey]);
          curr.setDate(curr.getDate()+1);
        }
        addMarked(Util.toDateString(curr), false, true, item[typeKey]);
      } else if(start.getTime() == end.getTime()) {
        addMarked(Util.toDateString(curr), true, true, item[typeKey]);
      }
    }

    if(typeof marked[now] === 'undefined') {
      marked[now] = { current: true };
    }

    return marked;
  }
  return {[Util.toDateString()]: {current: true}};
}

export const GetSectionData = (data, startDateKey='StartDate', endDateKey='EndDate') => {
  if(Array.isArray(data)) {
    let section = [];

    const addSection = (dateString, item) => {
      let found = section.find(x => x.title == dateString);
      if(!found) {
        found = { title: dateString, data:[] };
        section.push(found);
      }
      found.data.push(item);
    }

    for(const item of data) {
      const start = new Date(item[startDateKey]);
      const end = new Date(item[endDateKey]);
      
      let curr = new Date(start);
      while(curr.getTime() <= end.getTime()) {
        addSection(Util.toDateString(curr), item);
        curr.setDate(curr.getDate()+1);
      }
    }

    return section.sort((a,b) => a.date - b.date);
  }
  return [];
}

const agendaDefaultRenderItem = ({item}) => {
  return (
    <View style={{height:100,backgroundColor:'#f5f5f5'}}>
    </View>
  );
}
export const Calendar = ({
  current=null,
  minDate=null,
  maxDate=null,
  onDayPress=(day)=>{console.log('onDayPress...', day)},
  onDayLongPress=(day)=>{console.log('onDayLongPress...', day)},
  onMonthChange=(month)=>{},
  firstDay=0,
  data=[],
  dataStartDateKey='StartDate',
  dataEndDateKey='EndDate',
  dataTypeKey='Type',
  dataTypes=[],
  displayLoadingIndicator=false,
  agendaRenderItem=agendaDefaultRenderItem,
}) => {
  const [markedDates, setMarkedDates] = useState({[Util.toDateString()]:{current:true}});
  const [sections, setSections] = useState([]);
  const [selectedDate, setSelectedDate] = useState(null);

  useEffect(() => {
    const groupData = GetGroupingDate(data, dataStartDateKey, dataEndDateKey, dataTypeKey);
    const marked = ToMarkedDates(groupData, dataStartDateKey, dataEndDateKey, dataTypeKey);
    const sectionData = GetSectionData(data, dataStartDateKey, dataEndDateKey);

    setMarkedDates(marked);
    setSections(sectionData);
  }, [data, dataStartDateKey, dataEndDateKey, dataTypeKey]);

  const monthChangeHandler = (month) => {
    onMonthChange(month);
  }

  const getWeekData = (dateString) => {
    const date = new Date(dateString);
    const dayOfWeek = date.getDay();
    date.setDate(date.getDate()-dayOfWeek);

    let list = [];
    for(let i=0; i<=6; i++) {
      const currentDateString = Util.toDateString(date);
      const found = sections.find(x => x.title == currentDateString);
      if(found) {
        list.push(found);
      } else {
        list.push({title:currentDateString, data:[{}]});
      }
      date.setDate(date.getDate()+1);
    }
    return list;
  }
  const [weekData, setWeekData] = useState([]);
  const agendaList = useRef();
  useEffect(() => {
    if(selectedDate) {
      if(agendaList.current.getSectionIndex) {
        //const index = agendaList.current.getSectionIndex(selectedDate);
        //agendaList.current.scrollToSection(index);
      }
    }
  })

  return (
    <Fragment>
      {selectedDate ? (
        <CalendarProvider 
          date={selectedDate} 
          onDateChanged={(day)=>{
            setWeekData(getWeekData(day));
          }} 
          onMonthChange={monthChangeHandler}
          disabledOpacity={0.6}> 
          <AgendaContainer>
            <WeekCalendar
              firstDay={firstDay}
              allowShadow={false}
              monthFormat={'yyyy년 MM월'}
              markedDates={markedDates}
              onDayPress={(day) => {
                setWeekData(getWeekData(day.dateString));
                setSelectedDate(day.dateString);
                onDayPress(day);
              }}
              dayComponent={(props) => {
                return <DayComponent {...props} dataTypes={dataTypes} />
              }}/>
            <AgendaBar onPress={() => {
              setSelectedDate(null);
            }}><AgendaClose /></AgendaBar>
            <AgendaList
              //dayFormat="yyyy. MM. dd."
              sections={weekData}
              renderItem={agendaRenderItem}
              ref={agendaList}
              //extraData={this.state}
              // sectionStyle={styles.section}
            />
          </AgendaContainer>
        </CalendarProvider>
      ) : (
        <RNCalendar
          current={current}
          displayLoadingIndicator={displayLoadingIndicator}
          markedDates={markedDates}
          minDate={minDate}
          maxDate={maxDate}
          onDayPress={(day) => {
            setWeekData(getWeekData(day.dateString));
            setSelectedDate(day.dateString);
            onDayPress(day);
          }}
          onDayLongPress={onDayLongPress}
          onMonthChange={monthChangeHandler}
          firstDay={firstDay}
          monthFormat={'yyyy년 MM월'}
          renderArrow={(direction) => (direction=='left'?<Left width={18} height={18} />:<Right width={18} height={18} />)}
          dayComponent={(props) => {
            return <DayComponent {...props} dataTypes={dataTypes} />
          }}
        />
      )}
    </Fragment>
  )
}

const today = new Date().toISOString().split('T')[0];
const fastDate = getPastDate(3); 
const futureDates = getFutureDates(9);
const dates = [fastDate, today].concat(futureDates);
const themeColor = '#00AAAF';
const lightThemeColor = '#EBF9F9';

function getFutureDates(days) {
  const array = [];
  for (let index = 1; index <= days; index++) {
    const date = new Date(Date.now() + (864e5 * index)); // 864e5 == 86400000 == 24*60*60*1000
    const dateString = date.toISOString().split('T')[0];
    array.push(dateString);
  }
  return array;
}

function getPastDate(days) {
  return new Date(Date.now() - (864e5 * days)).toISOString().split('T')[0];
}

const ITEMS = [
  {title: dates[0], data: [{hour: '12am', duration: '1h', title: 'Ashtanga Yoga'}]},
  {title: dates[1], data: [{hour: '4pm', duration: '1h', title: 'Pilates ABC'}, {hour: '5pm', duration: '1h', title: 'Vinyasa Yoga'}]},
  {title: dates[2], data: [{hour: '1pm', duration: '1h', title: 'Ashtanga Yoga'}, {hour: '2pm', duration: '1h', title: 'Deep Streches'}, {hour: '3pm', duration: '1h', title: 'Private Yoga'}]},
  {title: dates[3], data: [{hour: '12am', duration: '1h', title: 'Ashtanga Yoga'}]},
  {title: dates[4], data: [{}]},
  {title: dates[5], data: [{hour: '9pm', duration: '1h', title: 'Pilates Reformer'}, {hour: '10pm', duration: '1h', title: 'Ashtanga'}, {hour: '11pm', duration: '1h', title: 'TRX'}, {hour: '12pm', duration: '1h', title: 'Running Group'}]},
  {title: dates[6], data: [{hour: '12am', duration: '1h', title: 'Ashtanga Yoga'}]},
  {title: dates[7], data: [{}]},
  {title: dates[8], data: [{hour: '9pm', duration: '1h', title: 'Pilates Reformer'}, {hour: '10pm', duration: '1h', title: 'Ashtanga'}, {hour: '11pm', duration: '1h', title: 'TRX'}, {hour: '12pm', duration: '1h', title: 'Running Group'}]},
  {title: dates[9], data: [{hour: '1pm', duration: '1h', title: 'Ashtanga Yoga'}, {hour: '2pm', duration: '1h', title: 'Deep Streches'}, {hour: '3pm', duration: '1h', title: 'Private Yoga'}]},
  {title: dates[10], data: [{hour: '12am', duration: '1h', title: 'Ashtanga Yoga'}]}
];

export default class ExpandableCalendarScreen extends Component {

  onDateChanged = (/* date, updateSource */) => {
    // console.warn('ExpandableCalendarScreen onDateChanged: ', date, updateSource);
    // fetch and set data for date + week ahead
  }

  onMonthChange = (/* month, updateSource */) => {
    // console.warn('ExpandableCalendarScreen onMonthChange: ', month, updateSource);
  }
  
  buttonPressed() {
    Alert.alert('show more');
  }

  itemPressed(id) {
    Alert.alert(id);
  }

  renderEmptyItem() {
    return (
      <View style={styles.emptyItem}>
        <Text style={styles.emptyItemText}>No Events Planned</Text>
      </View>
    );
  }

  renderItem = ({item}) => {
    if (_.isEmpty(item)) {
      return this.renderEmptyItem();
    }
    
    return (
      <TouchableOpacity 
        onPress={() => this.itemPressed(item.title)} 
        style={styles.item}
      >
        <View>
          <Text style={styles.itemHourText}>{item.hour}</Text>
          <Text style={styles.itemDurationText}>{item.duration}</Text>
        </View>
        <Text style={styles.itemTitleText}>{item.title}</Text>
        <View style={styles.itemButtonContainer}>
          <Button color={'grey'} title={'Info'} onPress={this.buttonPressed}/>
        </View>
      </TouchableOpacity>
    );
  }

  getMarkedDates = () => {
    const marked = {};
    ITEMS.forEach(item => {
      // NOTE: only mark dates with data
      if (item.data && item.data.length > 0 && !_.isEmpty(item.data[0])) {
        marked[item.title] = {marked: true};
      }
    });
    return marked;
  }

  render() {    
    return (
      <CalendarProvider 
        date={ITEMS[0].title} 
        onDateChanged={this.onDateChanged} 
        onMonthChange={this.onMonthChange}
        showTodayButton 
        disabledOpacity={0.6}
        // theme={{
        //   todayButtonTextColor: themeColor
        // }} 
        // todayBottomMargin={16}
      > 
        {this.props.weekView ? 
          <WeekCalendar
            firstDay={1}
            monthFormat={'yyyy년 MM월'}
            markedDates={this.getMarkedDates()}
          /> :
          <ExpandableCalendar 
            // horizontal={false}
            // hideArrows
            // disablePan
            // hideKnob
            // initialPosition={ExpandableCalendar.positions.OPEN}
            // calendarStyle={styles.calendar}
            // headerStyle={styles.calendar} // for horizontal only
            // disableWeekScroll
            // theme={this.getTheme()}
            firstDay={1}
            monthFormat={'yyyy년 MM월'}
            markedDates={this.getMarkedDates()} // {'2019-06-01': {marked: true}, '2019-06-02': {marked: true}, '2019-06-03': {marked: true}};
          />
        }
        <AgendaList
          sections={ITEMS}
          extraData={this.state}
          renderItem={this.renderItem}
          // sectionStyle={styles.section}
        />
      </CalendarProvider>
    );
  }
}

const styles = StyleSheet.create({
  calendar: {
    paddingLeft: 20, 
    paddingRight: 20
  },
  section: {
    backgroundColor: lightThemeColor, 
    color: 'grey',
    textTransform: 'capitalize'
  },
  item: {
    padding: 20, 
    backgroundColor: 'white', 
    borderBottomWidth: 1, 
    borderBottomColor: 'lightgrey', 
    flexDirection: 'row'
  },
  itemHourText: {
    color: 'black'
  },
  itemDurationText: {
    color: 'grey', 
    fontSize: 12, 
    marginTop: 4,
    marginLeft: 4
  },
  itemTitleText: {
    color: 'black', 
    marginLeft: 16, 
    fontWeight: 'bold', 
    fontSize: 16
  },
  itemButtonContainer: {
    flex: 1, 
    alignItems: 'flex-end'
  },
  emptyItem: {
    paddingLeft: 20,
    height: 52, 
    justifyContent: 'center',
    borderBottomWidth: 1, 
    borderBottomColor: 'lightgrey' 
  },
  emptyItemText: {
    color: 'lightgrey',
    fontSize: 14
  }
});