import { Button, Col, Row } from "antd";
import DotLoading from "components/DotLoading";
import DragDropContext from "components/DragDropContext";
import { AntInput, FieldType } from "components/Form/FormItem";
import { Icon, IconName } from "components/Icon";
import PodcastFieldItem from "components/PodcastFieldItem";
import PortalComponent from "components/PortalComponent/PortalComponent";
import { Paragraph } from "components/Typography";
import { Formik, Form, Field } from "formik";
import spotifyUri from "spotify-uri";

import {
  PodcastItem
} from "models/talent/talent-profile-module.model";
import * as React from "react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { MediaUpload } from "redux/Common/types";
import { useTypedSelector } from "redux/rootReducer";
import { selectUserData } from "redux/User/selector";
import { SocialProfileLinkTypes } from "redux/User/types";
import { validateEpisodeByType } from "utils/validate";
import CoverUpload from "./CoverUpload";
import PodcastDropdownService from "./PodcastDropdownService";
import copyToClipboard from "copy-to-clipboard";
import notification from "utils/notification";
import { useModules } from "hooks/useModules";
import reduce from "lodash/reduce";
import { spotifyService } from "services";
import { convertToUrl } from "utils/url";
import { defaultPodcastTags } from "constants/social";
import forEach from "lodash/forEach";
import config from "config";
import { ModuleType } from "@komi-app/shared-types"

interface IndividualPodcastContentProps {
  show?: boolean;
  step?: number;
  setStep?: (value: number) => void;
  item?: PodcastItem;
  cancellable?: boolean;
  close?: () => void;
  back?: () => void;
  callback: (values: any, action?: any) => void;
  onConnectSpotify?: () => void;
}
export const defaultPodcasts = [
  {
    key: SocialProfileLinkTypes.AMAZON_MUSIC,
    icon: "amazon-music",
    name: "Amazon Music",
  },
  {
    key: SocialProfileLinkTypes.APPLE_PODCAST,
    icon: "apple-podcast",
    name: "Apple Podcast",
  },
  {
    key: SocialProfileLinkTypes.AUDIBLE,
    icon: "audible",
    name: "Audible",
  },
  {
    key: SocialProfileLinkTypes.OVERCAST,
    icon: "overcast",
    name: "Overcast",
  },
  {
    key: SocialProfileLinkTypes.SPOTIFY,
    icon: "spotify",
    name: "Spotify",
  },
  {
    key: SocialProfileLinkTypes.STITCHER,
    icon: "stitcher",
    name: "Stitcher",
  },
];

const IndividualPodcastContent = ({
  show,
  step,
  setStep,
  item,
  cancellable,
  close,
  back,
  callback,
  onConnectSpotify,
}: IndividualPodcastContentProps) => {
  const [links, setLinks] = useState<any>([]);
  const [loading, setLoading] = useState(false);
  const { modules } = useModules();
  const [submitData, setSubmitData] = useState<any>({});
  const [initValues, setInitValues] = useState({});
  const [errors, setErrors] = useState<any>({});
  const [photo, setPhoto] = useState<any>({});
  const [previewUrl, setPreviewUrl] = useState("");
  const user = useTypedSelector(selectUserData);
  const caption = useMemo(() => {
    return !!item || cancellable
      ? step === 1
        ? "CANCEL"
        : "PREVIOUS"
      : "PREVIOUS";
  }, [item, cancellable, step]);
  useEffect(() => {
    if (show) {
      if (item) {
        const editLinks: any = item.links.map((item: any) => {
          const link = defaultPodcastTags.find((el) => el.key === item.type);
          return { ...link, value: item.url };
        });
        setLinks(editLinks);
        setPhoto({ url: item.metadata?.images?.[0]?.url });
        const initValues = item.links.reduce((values: any, item: any) => {
          return { ...values, [item.type as string]: item.url };
        }, {});
        setPreviewUrl(item.metadata?.previewUrl);
        setInitValues(initValues);
        return;
      }
    }
  }, [item, show]);
  const podcastItems = useMemo(
    () =>
      reduce(
        modules,
        (results: any, item: any) => {
          if (item.type === ModuleType.GROUP) {
            const items = item.items.filter(
              (el: any) => el.type === ModuleType.PODCAST
            );
            const data = reduce(
              items,
              (result: any, module: any) => {
                return [...result, ...module.items];
              },
              []
            );

            return [...results, ...data];
          }
          if (item.type === ModuleType.PODCAST) {
            return [...results, ...item.items];
          }
          return results;
        },
        []
      ),
    [modules]
  );
  const actionBack = useCallback(() => {
    if (step === 2) {
      setStep?.(1);
      setTimeout(() => {
        const initValues = submitData.links?.reduce(
          (values: any, item: any) => {
            return { ...values, [item.type as string]: item.url };
          },
          {}
        );
        setInitValues({
          ...initValues,
          name: "",
          publisher: "",
          customUrl: "",
        });
        setPhoto({});
        setErrors({});
      }, 50);
      return;
    }
    if (!!item || cancellable) {
      close?.();
      return;
    }
    back?.();
  }, [item, close, back, cancellable, step, submitData]);
  const onDropEndModules = (list: any) => {
    setLinks(list);
  };
  const onClickMenu = (item: any) => {
    setErrors({});
    setLinks((values: any) => [...values, { ...item, url: "" }]);
  };
  const handleSpotifyMetadata = useCallback(
    async (result: any) => {
      const { response } = result;

      setPhoto({ url: response?.images[1]?.url || response?.images[0]?.url });
      setPreviewUrl(response?.audio_preview_url);
      setInitValues(
        item
          ? {
              publisher: response?.show?.publisher || "",
              name: response?.name,
              customUrl: item?.customUrl || "",
            }
          : {
              publisher: response?.show?.publisher || "",
              name: response?.name,
              customUrl: convertToUrl(response?.name),
            }
      );
      setStep?.(2);
    },
    [setStep, item]
  );
  const onSubmit = async (values: any) => {
    if (!links.length) {
      setErrors({
        empty: true,
      });
      return;
    }

    if (step === 1) {
      const podcastLinks = links.map((link: any) => ({
        type: link.key,
        url: values[link.key],
        active: link.active,
      }));
      setSubmitData({
        links: podcastLinks,
      });
      if (values.SPOTIFY) {
        try {
          setLoading(true);
          const isToken = await onConnectSpotify?.();

          if (!isToken) {
            notification.success({
              message: "Connection to spotify is failed",
            });
            return;
          }
          const oldSpotify = item?.links.find(
            (el: any) => el.type === SocialProfileLinkTypes.SPOTIFY
          );
          if (oldSpotify?.url === values.SPOTIFY) {
            setStep?.(2);
            setPhoto({ url: item?.metadata?.images?.[0].url });
            setInitValues((values) => ({
              ...values,
              name: item?.metadata?.name || "",
              publisher: item?.metadata?.publisher || "",
              customUrl:
                item?.customUrl ||
                (item?.metadata?.name
                  ? convertToUrl(item?.metadata?.name)
                  : ""),
            }));
            return;
          }
          const uri: any = spotifyUri.parse(values.SPOTIFY);

          if (uri.type !== "episode") {
            setStep?.(2);
            return;
          }
          const result: any = await spotifyService.getSpotifyById(
            `${uri.type}s`,
            uri.id || uri.user
          );
          if (result && "ok" in result) {
            handleSpotifyMetadata(result);
          } else {
            throw result;
          }
        } catch (error) {
          setStep?.(2);
        } finally {
          setLoading(false);
        }
        return;
      }
      setStep?.(2);
      return;
    }
    if (!photo.url) {
      setErrors({
        photo: true,
      });
      return;
    }
    const metadata = {
      name: values.name,
      images: [{ url: photo.url }],
      publisher: values.publisher,
      previewUrl,
    };

    const data = {
      ...submitData,
      customUrl: values.customUrl,
      metadata,
    };
    callback?.(data);
  };
  const onDeletePodcastItem = useCallback(
    (key: string, action: any) => () => {
      setLinks((values: any) => values.filter((el: any) => el.key !== key));
      action.setFieldValue(key, "");
      action.setFieldTouched(key, false, false);
    },
    []
  );
  const uploadPhotoSuccess = (file: MediaUpload) => {
    setErrors({});
    setPhoto(file);
  };

  const removePhoto = () => {
    setPhoto({});
  };
  const komiLink = useMemo(() => {
    return config.service.env === "development"
      ? `https://${user?.username}-dev.komi.io`
      : config.service.env === "staging"
      ? `https://${user?.username}-staging.komi.io`
      : `https://${user?.username}.komi.io`;
  }, [user]);

  const onCopyLink = useCallback(
    (path: string) => () => {
      if (!path) {
        return;
      }
      const regex = new RegExp("^[a-zA-Z0-9-_]*$");
      if (!regex.test(path)) {
        return;
      }
      if (
        (item && item.customUrl === path) ||
        !podcastItems.some((podcast: any) => podcast.customUrl === path)
      ) {
        copyToClipboard(`${komiLink}/podcast/${path}`);
        notification.success({
          message:
            "The smart link has been copied to clipboard. Your updates need to be published before the link can be accessed.",
        });
        return;
      }
    },
    [komiLink, podcastItems]
  );

  const renderPodcastList = (action: any) => {
    return (
      <React.Fragment>
        <DragDropContext
          droppableId="modules-drop"
          listClassName={"modules-list m__t--24"}
          itemIdPrefix="module"
          list={links}
          onDropEndCallback={onDropEndModules}
        >
          {(dragProvided, snapshot, podcast: any) => (
            <PortalComponent
              innerRef={dragProvided.innerRef}
              namespaceClass="module-list"
              provided={dragProvided}
              snapshot={snapshot}
            >
              <PodcastFieldItem
                icon={podcast.icon as IconName}
                name={podcast.key}
                title={podcast.name}
                dragHandleProps={dragProvided.dragHandleProps}
                isDisableDragged={links.length === 1}
                placeholder="Enter episode link"
                validate={validateEpisodeByType(podcast.key)}
                rightContent={
                  <Button
                    onClick={onDeletePodcastItem(podcast.key, action)}
                    className="p--0"
                    type="text"
                  >
                    <div className="height--24">
                      <Icon name="trash" />
                    </div>
                  </Button>
                }
                rightContentClassName="height--24"
              />
            </PortalComponent>
          )}
        </DragDropContext>
      </React.Fragment>
    );
  };
  const validateString = (message: string) => (value: string) => {
    if (!value) {
      return message;
    }
    return;
  };
  const validatePathLink = async (value: string) => {
    if (!value) {
      return "Please enter a valid URL";
    }
    const regex = new RegExp("^[a-zA-Z0-9-_]*$");
    if (!regex.test(value)) {
      return "Custom URL can only contain letters, numbers, '_', or '-'";
    }
    if (item && item.customUrl === value) {
      return;
    }
    if (podcastItems.some((podcast: any) => podcast.customUrl === value)) {
      return "This URL is already being used";
    }
    return;
  };
  const onBeforeSubmit = useCallback(
    (action) => () => {
      if (step === 1) {
        forEach(links, (item) => {
          if (!action.values[item.key]) {
            action.setFieldValue(item.key, "", true);
          }
        });
        return;
      }
      if (!action.values.name) {
        action.setFieldValue("name", "", true);
      }
      if (!action.values.publisher) {
        action.setFieldValue("publisher", "", true);
      }
      if (!action.values.customUrl) {
        action.setFieldValue("customUrl", "", true);
      }

      if (!photo.url) {
        setErrors({
          photo: true,
        });
      }
    },
    [photo, step, links]
  );

  const renderContent = (props: any) => {
    if (step === 2) {
      return (
        <div>
          <Paragraph className="m__b--24" preset="semibold18">
            Customize Link
          </Paragraph>

          <CoverUpload
            photo={photo}
            onUploadSuccess={uploadPhotoSuccess}
            onRemove={removePhoto}
            error={errors.photo}
          />
          <Field
            className="m__t--24"
            component={AntInput}
            name={"name"}
            type={FieldType.input}
            placeholder={"e.g. Episode 1"}
            label="Episode title"
            validate={validateString("Please add an episode title")}
          />
          <Field
            className="m__t--24"
            component={AntInput}
            name={"publisher"}
            type={FieldType.input}
            placeholder={"e.g. iHeartRadio"}
            label="Author or publisher"
            validate={validateString("Please add an author or publisher")}
          />
          <Paragraph className="text--tudona m__t--24" preset="regular14">
            Custom URL
          </Paragraph>
          <Row gutter={16}>
            <Col flex="1">
              <Field
                className="m__t--4"
                component={AntInput}
                formItemClassName="m__b--0 link-field"
                name={"customUrl"}
                type={FieldType.input}
                placeholder={"e.g. episode-1"}
                addonBefore={komiLink}
                validate={validatePathLink}
              />
            </Col>
            <Col className="p__t--18">
              <Button
                onClick={onCopyLink(props.values.customUrl)}
                className="p--0"
                type="text"
              >
                <div className="height--24">
                  <Icon name="copy-link" />
                </div>
              </Button>
            </Col>
          </Row>
        </div>
      );
    }
    return (
      <div>
        <Paragraph preset="semibold18">Select Services</Paragraph>
        {renderPodcastList(props)}
        <PodcastDropdownService
          onClickMenu={onClickMenu}
          links={links}
          menuItems={defaultPodcasts}
        />
        {errors.empty && (
          <Paragraph className="text--red m__t--8" preset="regular12">
            Please add at least one service
          </Paragraph>
        )}
      </div>
    );
  };

  return (
    <div className="relative">
      <Formik enableReinitialize initialValues={initValues} onSubmit={onSubmit}>
        {(props) => (
          <Form onSubmit={props.handleSubmit}>
            {renderContent(props)}
            <Row className="m__y--24" gutter={16} justify="end" align="middle">
              <Col>
                <Button
                  className="height--52 width--160 text__transform--uppercase letter__spacing--1"
                  type="default"
                  block
                  onClick={() => {
                    actionBack();
                    props.handleReset();
                  }}
                  size="large"
                >
                  {caption}
                </Button>
              </Col>
              <Col>
                <Button
                  className="height--52 width--160 text__transform--uppercase letter__spacing--1"
                  type="primary"
                  block
                  size="large"
                  htmlType="submit"
                  onClick={onBeforeSubmit(props)}
                >
                  {step === 2 ? "DONE" : "NEXT"}
                </Button>
              </Col>
            </Row>
          </Form>
        )}
      </Formik>
      {loading && (
        <Row className="loading-content" justify="space-between" align="middle">
          <DotLoading />
        </Row>
      )}
    </div>
  );
};

export default IndividualPodcastContent;
