'use client';

import React, { useEffect, useMemo, useState } from 'react';
import { Button } from '@/components/ui/buttons';
import { Input } from '@/components/ui/inputs';
import { Separator } from '@/components/ui/seperator';
import { Switch } from '@/components/ui/switch';
import { PulseLoader } from '@/components/ui/loaders';
import { useMemoizedFn } from '@/hooks';
import { createDayjsDate } from '@/lib/date';
import { BusterRoutes, createBusterRoute } from '@/routes';
import { ShareAssetType } from '@/api/asset_interfaces';
import { Text } from '@/components/ui/typography';
import { useBusterNotifications } from '@/context/BusterNotifications';
import { Link, Eye, EyeSlash } from '@/components/ui/icons';
import { DatePicker } from '@/components/ui/date';
import { useUpdateCollectionShare } from '@/api/buster_rest/collections';
import { useUpdateMetricShare } from '@/api/buster_rest/metrics';
import { useUpdateDashboardShare } from '@/api/buster_rest/dashboards';
import { SelectSingleEventHandler } from 'react-day-picker';
import { ShareMenuContentBodyProps } from './ShareMenuContentBody';
import { cn } from '@/lib/classMerge';

export const ShareMenuContentPublish: React.FC<ShareMenuContentBodyProps> = React.memo(
  ({
    assetType,
    assetId,
    password = '',
    publicly_accessible,
    onCopyLink,
    publicExpirationDate,
    className
  }) => {
    const { openInfoMessage } = useBusterNotifications();
    const { mutateAsync: onShareMetric, isPending: isPublishingMetric } = useUpdateMetricShare();
    const { mutateAsync: onShareDashboard, isPending: isPublishingDashboard } =
      useUpdateDashboardShare();
    const { mutateAsync: onShareCollection, isPending: isPublishingCollection } =
      useUpdateCollectionShare();
    const [isPasswordProtected, setIsPasswordProtected] = useState<boolean>(!!password);
    const [_password, _setPassword] = React.useState<string>(password || '');

    const isPublishing = isPublishingMetric || isPublishingDashboard || isPublishingCollection;

    const linkExpiry = useMemo(() => {
      return publicExpirationDate ? new Date(publicExpirationDate) : null;
    }, [publicExpirationDate]);

    const url = useMemo(() => {
      let url = '';
      if (assetType === ShareAssetType.METRIC) {
        url = createBusterRoute({ route: BusterRoutes.APP_METRIC_ID_CHART, metricId: assetId });
      } else if (assetType === ShareAssetType.DASHBOARD) {
        url = createBusterRoute({ route: BusterRoutes.APP_DASHBOARD_ID, dashboardId: assetId });
      } else if (assetType === ShareAssetType.COLLECTION) {
        url = createBusterRoute({ route: BusterRoutes.APP_COLLECTIONS });
      }
      return window.location.origin + url;
    }, [assetId, assetType]);

    const onTogglePublish = useMemoizedFn(async (v?: boolean) => {
      const linkExp = linkExpiry ? linkExpiry.toISOString() : null;
      const payload: Parameters<typeof onShareMetric>[0] = {
        id: assetId,
        params: {
          publicly_accessible: v === undefined ? true : !!v,
          public_password: _password || null,
          public_expiry_date: linkExp
        }
      };
      if (assetType === ShareAssetType.METRIC) {
        await onShareMetric(payload);
      } else if (assetType === ShareAssetType.DASHBOARD) {
        await onShareDashboard(payload);
      } else if (assetType === ShareAssetType.COLLECTION) {
        await onShareCollection(payload);
      }
    });

    const onSetPasswordProtected = useMemoizedFn(async (v: boolean) => {
      onSetPassword(null);
      setIsPasswordProtected(v);
    });

    const onSetPassword = useMemoizedFn(async (password: string | null) => {
      const payload: Parameters<typeof onShareMetric>[0] = {
        id: assetId,
        params: {
          public_password: password
        }
      };

      if (assetType === ShareAssetType.METRIC) {
        await onShareMetric(payload);
      } else if (assetType === ShareAssetType.DASHBOARD) {
        await onShareDashboard(payload);
      } else if (assetType === ShareAssetType.COLLECTION) {
        await onShareCollection(payload);
      }
      _setPassword(password || '');
      if (password) openInfoMessage('Password updated');
    });

    const onSetExpirationDate = useMemoizedFn(async (date: Date | null) => {
      const linkExp = date ? date.toISOString() : null;

      const payload: Parameters<typeof onShareMetric>[0] = {
        id: assetId,
        params: {
          public_expiry_date: linkExp
        }
      };

      if (assetType === ShareAssetType.METRIC) {
        await onShareMetric(payload);
      } else if (assetType === ShareAssetType.DASHBOARD) {
        await onShareDashboard(payload);
      } else if (assetType === ShareAssetType.COLLECTION) {
        await onShareCollection(payload);
      }
    });

    useEffect(() => {
      _setPassword(password || '');
      setIsPasswordProtected(!!password);
    }, [password]);

    return (
      <div className="flex flex-col space-y-1">
        <div className={cn('flex flex-col space-y-3', className)}>
          {publicly_accessible ? (
            <>
              <IsPublishedInfo isPublished={publicly_accessible} />

              <div className="flex w-full space-x-0.5">
                <Input size="small" readOnly value={url} />
                <Button variant="default" className="flex" prefix={<Link />} onClick={onCopyLink} />
              </div>

              <LinkExpiration linkExpiry={linkExpiry} onChangeLinkExpiry={onSetExpirationDate} />

              <SetAPassword
                password={_password}
                onSetPassword={onSetPassword}
                isPasswordProtected={isPasswordProtected}
                onSetPasswordProtected={onSetPasswordProtected}
              />
            </>
          ) : (
            <div className="flex flex-col space-y-2.5">
              <Text variant="secondary">Anyone with the link will be able to view.</Text>

              <Button
                loading={isPublishing}
                onClick={() => {
                  onTogglePublish(true);
                }}>
                Create public link
              </Button>
            </div>
          )}
        </div>

        {publicly_accessible && (
          <>
            <div className={cn('flex justify-end space-x-2 border-t', className)}>
              <Button
                block
                onClick={async (v) => {
                  onTogglePublish(false);
                }}>
                Unpublish
              </Button>
              <Button block onClick={onCopyLink}>
                Copy link
              </Button>
            </div>
          </>
        )}
      </div>
    );
  }
);
ShareMenuContentPublish.displayName = 'ShareMenuContentPublish';

const IsPublishedInfo: React.FC<{ isPublished: boolean }> = React.memo(({ isPublished }) => {
  if (!isPublished) return null;

  return (
    <div className="flex items-center space-x-2">
      <PulseLoader />
      <Text variant="link">Live on the web</Text>
    </div>
  );
});
IsPublishedInfo.displayName = 'IsPublishedInfo';

const LinkExpiration: React.FC<{
  linkExpiry: Date | null;
  onChangeLinkExpiry: (date: Date | null) => void;
}> = React.memo(({ onChangeLinkExpiry, linkExpiry }) => {
  const dateFormat = 'LL';

  const now = useMemo(() => {
    return createDayjsDate(new Date());
  }, []);

  const maxDate = useMemo(() => {
    return createDayjsDate(new Date()).add(2, 'year');
  }, []);

  const onSelect = useMemoizedFn((date: Date | undefined) => {
    onChangeLinkExpiry(date || null);
  });

  return (
    <div className="flex items-center justify-between space-x-2">
      <Text truncate>Link expiration</Text>

      <DatePicker
        selected={linkExpiry || undefined}
        onSelect={onSelect}
        mode="single"
        dateFormat={dateFormat}
        placeholder="Never"
        disabled={(date) => {
          const dateValue = createDayjsDate(date);
          return dateValue.isBefore(now) || dateValue.isAfter(maxDate);
        }}
      />
    </div>
  );
});
LinkExpiration.displayName = 'LinkExpiration';

const SetAPassword: React.FC<{
  password: string;
  onSetPassword: (password: string | null) => void;
  isPasswordProtected: boolean;
  onSetPasswordProtected: (isPasswordProtected: boolean) => void;
}> = React.memo(
  ({ password: passwordProp, onSetPassword, isPasswordProtected, onSetPasswordProtected }) => {
    const [visibilityToggle, setVisibilityToggle] = useState<boolean>(false);
    const [password, setPassword] = useState<string>(passwordProp);

    const isPasswordDifferent = password !== passwordProp;

    const onChangeChecked = useMemoizedFn((checked: boolean) => {
      onSetPasswordProtected(checked);
    });

    const onChangePassword = useMemoizedFn((e: React.ChangeEvent<HTMLInputElement>) => {
      setPassword(e.target.value);
    });

    const onClickVisibilityToggle = useMemoizedFn(() => {
      setVisibilityToggle(!visibilityToggle);
    });

    const onClickSave = useMemoizedFn(() => {
      onSetPassword(password);
    });

    const memoizedVisibilityToggle = useMemo(() => {
      return {
        visible: visibilityToggle,
        onVisibleChange: (visible: boolean) => setVisibilityToggle(visible)
      };
    }, [visibilityToggle]);

    useEffect(() => {
      if (isPasswordProtected) {
        setPassword(password);
      } else {
        setPassword('');
      }
    }, [isPasswordProtected, password]);

    return (
      <div className="flex w-full flex-col space-y-3">
        <div className="flex w-full justify-between">
          <Text>Set a password</Text>
          <Switch checked={isPasswordProtected} onCheckedChange={onChangeChecked} />
        </div>

        {isPasswordProtected && (
          <div className="flex w-full items-center space-x-2">
            <div className="flex w-full">
              <div className="relative flex w-full space-x-0.5">
                <Input
                  value={password}
                  onChange={onChangePassword}
                  placeholder="Password"
                  type={visibilityToggle ? 'text' : 'password'}
                />

                <Button
                  variant="ghost"
                  size="small"
                  className="absolute top-1/2 right-[7px] -translate-y-1/2"
                  prefix={!visibilityToggle ? <Eye /> : <EyeSlash />}
                  onClick={onClickVisibilityToggle}></Button>
              </div>
            </div>

            <Button disabled={!isPasswordDifferent} onClick={onClickSave}>
              Save
            </Button>
          </div>
        )}
      </div>
    );
  }
);

SetAPassword.displayName = 'SetAPassword';
