import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { StyledLayout, Interactable, Text, Color } from 'twitch-core-ui';

import { Dropdown } from 'mweb/common/components/buttons/dropdown';
import { NotificationRequest } from 'mweb/common/actions/pages/eventDetails';
import { Location } from 'mweb/common/reducers/app';
import {
  withTracking,
  TrackingProps,
  UITrackingParameters,
} from 'mweb/common/tracking/withTracking';

const GOOGLE_BASE_URL =
  'https://www.google.com/calendar/render?target=_blank&action=TEMPLATE&';

const MOBILE_GOOGLE_CALENDAR_BASE_URL =
  'https://calendar.google.com/calendar/gp#~calendar:view=e&bm=1&trp=false&action=TEMPLATE&target=_blank&';

const INTERACTION_MEDIUM_MENU = 'remind_me_menu';
export const INTERACTION_CONTENT_REMIND_ME = 'remind_me';
export const INTERACTION_CONTENT_GOOGLE_CAL = 'google_calendar';
export const INTERACTION_CONTENT_APPLE_CAL = 'apple_calendar';

export interface RemindMeButtonValueProps {
  startTime: Date;
  endTime: Date;
  title: string;
  description: string;
  isMobileOS: boolean;
  appLocation: Location;
}

export interface RemindMeButtonDispatchProps {
  handleNotificationRequest: (request: string, location: Location) => void;
}

export interface RemindMeButtonProps
  extends RemindMeButtonValueProps,
    RemindMeButtonDispatchProps,
    TrackingProps {}

interface RemindMeMenuItemData {
  text: string;
  onClick?: React.EventHandler<React.MouseEvent<HTMLButtonElement>>;
  tracking?: UITrackingParameters;
}

export interface RemindMeMenuItemProps
  extends RemindMeMenuItemData,
    TrackingProps {}

export function RemindMeMenuItemBase(
  props: RemindMeMenuItemProps,
): JSX.Element {
  const onClick = props.tracking
    ? props.trackClick(props.tracking, props.onClick)
    : props.onClick;

  return (
    <Interactable onClick={onClick} key={props.text}>
      <StyledLayout padding={{ x: 1, y: 0.5 }} color={Color.Link}>
        <Text>{props.text}</Text>
      </StyledLayout>
    </Interactable>
  );
}

const RemindMeMenuItem = withTracking(RemindMeMenuItemBase);

export class RemindMeButtonBase extends React.PureComponent<
  RemindMeButtonProps,
  {}
> {
  noteNotificationRequested = (request: NotificationRequest): void => {
    this.props.handleNotificationRequest(request, this.props.appLocation);
  };

  notifyOfInitialDropdown = (e: React.MouseEvent<HTMLButtonElement>): void => {
    if (e && e.currentTarget) {
      e.currentTarget.blur();
    }
    this.noteNotificationRequested('remind_me_open_modal');
  };

  addGoogleCalendar = (): void => {
    const range = `${convertDateToSpecialString(
      this.props.startTime,
    )}/${convertDateToSpecialString(this.props.endTime)}`;
    const e = (param: string) => encodeURIComponent(param);
    const url = `${pickGoogleCalendarURL(this.props.isMobileOS)}text=${e(
      this.props.title,
    )}&dates=${e(range)}&details=${e(this.props.description)}`;
    this.noteNotificationRequested('google_calendar');
    window.open(url);
  };

  addAppleCalendar = (): void => {
    const start = new Date(this.props.startTime);
    const end = new Date(this.props.endTime);
    const ics = `BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Twitch.tv//NONSGML Event//EN
BEGIN:VEVENT
UID:${start.toUTCString()}@www.twitch.tv
DTSTAMP:${convertDateToSpecialString(new Date())}
DTSTART:${convertDateToSpecialString(start)}
DTEND:${convertDateToSpecialString(end)}
SUMMARY:${this.props.title}
DESCRIPTION:${this.props.description}
END:VEVENT
END:VCALENDAR`;
    this.noteNotificationRequested('apple_calendar');
    download(ics);
  };

  get dropdownItems(): [RemindMeMenuItemData] {
    return [
      {
        text: 'Google Calendar',
        onClick: this.addGoogleCalendar,
        tracking: {
          interactionContent: INTERACTION_CONTENT_GOOGLE_CAL,
        },
      },
      {
        text: 'Apple Calendar',
        onClick: this.addAppleCalendar,
        tracking: {
          interactionContent: INTERACTION_CONTENT_APPLE_CAL,
        },
      },
    ];
  }

  render(): JSX.Element | false {
    return (
      new Date(this.props.endTime) > new Date() && (
        <Dropdown
          onClick={this.props.trackClick(
            {
              interactionContent: INTERACTION_CONTENT_REMIND_ME,
            },
            this.notifyOfInitialDropdown,
          )}
          interactionMedium={INTERACTION_MEDIUM_MENU}
          dropdownItems={this.dropdownItems.map(createRemindMeMenuItem)}
        >
          <FormattedMessage
            id="add-reminder-button--top-level-message"
            defaultMessage="Remind Me"
          />
        </Dropdown>
      )
    );
  }
}

function createRemindMeMenuItem(data: RemindMeMenuItemData): JSX.Element {
  return (
    <RemindMeMenuItem
      onClick={data.onClick}
      tracking={data.tracking}
      text={data.text}
      key={data.text}
    />
  );
}

// Format is required by google and ICAL format.
// Basically UTC without -, :, and milliseconds, so this:
// '2017-03-23T00:00:00.123Z' is converted to this:
// '20170323T000000Z'
function convertDateToSpecialString(date: Date): string {
  return new Date(date)
    .toISOString()
    .replace(/[-:]/g, '')
    .replace(/\.\d+Z/, 'Z');
}

function pickGoogleCalendarURL(isMobileOS: boolean): string {
  if (isMobileOS) {
    return GOOGLE_BASE_URL;
  } else {
    return MOBILE_GOOGLE_CALENDAR_BASE_URL;
  }
}

function download(ics: string): void {
  let fileName = 'event.ics';

  if (typeof window.navigator.msSaveBlob === 'function') {
    // IE 10+
    let blob = new Blob([ics], { type: 'text/calendar;charset=utf-8;' });

    window.navigator.msSaveBlob(blob, fileName);
    return;
  }

  let anchor = document.createElement('a');
  let encodedURI = encodeURIComponent(ics);

  // Firefox, Chrome (HTML5)
  anchor.href = `data:text/calendar;charset=utf-8,${encodedURI}`;
  anchor.download = fileName;

  anchor.target = '_blank';

  document.body.appendChild(anchor);
  anchor.click();
  document.body.removeChild(anchor);
}

export const RemindMeButton = withTracking(RemindMeButtonBase);
