'use client';

/* eslint jsx-a11y/click-events-have-key-events: warn */

/* eslint jsx-a11y/no-static-element-interactions: warn */
import { useMutation } from '@tanstack/react-query';
import { observer } from 'mobx-react-lite';
import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { useStores } from '@/app/(root)/AppProviders';
import Modal from '@/components/modal/Modal';
import { toast } from '@/components/toast/Toast';
import { useApiClient } from '@/lib/apiClient';
import {
  FEEDBACK_FORM_RATINGS,
  FEEDBACK_OPTIONS,
  FEEDBACK_TESTER_APPLICATION_URL,
} from '@/utils/constants';

import Button from '../button/Button';
import Link from '../link/Link';

enum FeedbackOption {
  RESET = -1,
  BUG_REPORT = 0,
  IDEAS = 1,
  BILLING = 2,
  TESTER = 3,
}

enum Platform {
  IOS = 'ios',
  ANDROID = 'android',
  WEB = 'web',
  MOBILE_WEB = 'mobile_web',
}

interface FeedbackFormData {
  rating: number;
  feedback: string;
  mediaLink: string;
  platform: Platform;
  browser: string;
  link: string;
  stepsToReproduce: string;
}

interface FeedbackFormProps {
  onClose: () => void;
}
interface RatingsProps {
  data: FeedbackFormData;
  setData: React.Dispatch<React.SetStateAction<FeedbackFormData>>;
}
interface BugReportInputProps {
  data: FeedbackFormData;
  setData: React.Dispatch<React.SetStateAction<FeedbackFormData>>;
}
interface SimpleTextInputProps {
  data: FeedbackFormData;
  setData: React.Dispatch<React.SetStateAction<FeedbackFormData>>;
}

interface FeedbackInputProps {
  feedbackOption: number;
  data: FeedbackFormData;
  setData: React.Dispatch<React.SetStateAction<FeedbackFormData>>;
}

interface FeedbackOptionProps {
  feedbackOption: FeedbackOption;
  setFeedbackOption: React.Dispatch<React.SetStateAction<number>>;
}

const MandatoryIndicator = ({
  isMandatory = true,
}: {
  isMandatory?: boolean;
}) => {
  return isMandatory ? (
    <span className='text-accent-error-on-primary'> *</span>
  ) : (
    <span className='text-xs text-secondary'> (optional)</span>
  );
};

const FeedbackOptions = ({
  feedbackOption,
  setFeedbackOption,
}: FeedbackOptionProps) => {
  const { t } = useTranslation();
  const options = [
    { key: FEEDBACK_OPTIONS.BUG_REPORT, value: t('feedback.broken') },
    { key: FEEDBACK_OPTIONS.IDEAS, value: t('feedback.idea') },
    { key: FEEDBACK_OPTIONS.BILLING, value: t('feedback.billing') },
    { key: FEEDBACK_OPTIONS.TESTER, value: t('feedback.tester') },
  ];

  return (
    <section className='flex flex-col gap-4'>
      <div className='flex w-full flex-col justify-between gap-4 text-center'>
        {options.map((option) => (
          <div
            onClick={() => setFeedbackOption(option.key)}
            title={option.value}
            key={option.key}
            className='flex w-full cursor-pointer items-center gap-2'
          >
            <div
              className={`h-6 w-6 cursor-pointer rounded-full border border-secondary transition ease-linear ${feedbackOption === option.key ? 'bg-secondary' : 'bg-transparent'} `}
            />
            <h3 className='text-xs text-secondary lg:text-sm'>
              {option.value}
            </h3>
          </div>
        ))}
      </div>
    </section>
  );
};

const Ratings = ({ data, setData }: RatingsProps) => {
  return (
    <section className='flex flex-col gap-4'>
      <div className='flex flex-col gap-2 text-xs text-secondary lg:text-sm'>
        <span>We love hearing from our users!</span>
        <span>
          As a reminder, this is for feedback only. For support requests (e.g.
          urgent issues with your account or credits), please email{' '}
          <a
            className='text-primary underline hover:text-secondary'
            href='mailto:support@suno.com'
          >
            support@suno.com
          </a>
        </span>
        <span>
          How would you rate your overall experience with Suno?
          <MandatoryIndicator />
        </span>
      </div>
      <div className='flex w-full flex-row justify-between gap-4 text-center'>
        {FEEDBACK_FORM_RATINGS.map((rating) => (
          <div
            key={rating.value}
            onClick={() => {
              setData({ ...data, rating: rating.value });
            }}
            title={rating.label}
            className='flex w-full cursor-pointer flex-col items-center gap-2'
          >
            <div
              className={`h-8 w-8 cursor-pointer rounded-full border border-secondary transition ease-linear ${
                data.rating == rating.value
                  ? 'bg-secondary'
                  : 'bg-transparent hover:bg-secondary'
              }`}
            />
            <h3 className='text-xs text-secondary lg:text-sm'>
              {rating.label}
            </h3>
          </div>
        ))}
      </div>
    </section>
  );
};

const BugReportInput = ({ data, setData }: BugReportInputProps) => {
  const [mediaLink, setMediaLink] = useState('');
  const [platform, setPlatform] = useState<string>(Platform.WEB);
  const [browser, setBrowser] = useState('');
  const [link, setLink] = useState('');
  const [stepsToReproduce, setStepsToReproduce] = useState('');
  const webPlatforms = [Platform.WEB, Platform.MOBILE_WEB];
  const mobilePlatforms = [Platform.IOS, Platform.ANDROID];
  const fields = [
    {
      id: 'platform',
      label: 'What platform did you experience the issue on?',
      value: platform,
      setValue: setPlatform,
      type: 'select',
      isMandatory: true,
      options: [
        { label: 'Web', value: Platform.WEB },
        { label: 'Mobile Web', value: Platform.MOBILE_WEB },
        { label: 'iOS App', value: Platform.IOS },
        { label: 'Android App', value: Platform.ANDROID },
      ],
    },
    {
      id: 'browser',
      label: 'What browser did you experience the issue on?',
      placeholder: 'e.g. Safari 18.2, Chrome 123, Firefox 136, etc.',
      value: browser,
      setValue: setBrowser,
      type: 'input',
      isMandatory: true,
      hideIf: !webPlatforms.includes(platform as Platform),
    },
    {
      id: 'mediaLink',
      label: 'Link to a screenshot or recording',
      placeholder: 'Provide a link to a screenshot or recording of the issue',
      value: mediaLink,
      setValue: setMediaLink,
      type: 'input',
      isMandatory: false,
    },
    {
      id: 'link',
      label: 'Song/Page Link',
      placeholder:
        'Paste a link to the song/page where you experienced the issue',
      value: link,
      setValue: setLink,
      type: 'input',
      isMandatory: !mobilePlatforms.includes(platform as Platform),
    },
    {
      id: 'stepsToReproduce',
      label: 'Steps to reproduce',
      placeholder:
        'What were you trying to do? What happened instead? What page were you on? What did you click on? Help us reproduce it so we can fix it!',
      value: stepsToReproduce,
      setValue: setStepsToReproduce,
      type: 'textarea',
      isMandatory: true,
    },
  ];
  return (
    <section className='flex flex-col gap-4 text-sm text-foreground-secondary lg:text-base'>
      {fields.map((field) =>
        field.type === 'input' && !field.hideIf ? (
          <div key={field.id} className='flex flex-col gap-1'>
            <span className='text-xs lg:text-sm'>
              {field.label}
              <MandatoryIndicator isMandatory={field.isMandatory} />
            </span>
            <input
              className='relative w-full rounded-md bg-background-tertiary p-2 text-xs placeholder:text-xs lg:text-sm lg:placeholder:text-sm'
              type={field.type}
              placeholder={field.placeholder}
              value={field.value}
              onChange={(e) => {
                field.setValue(e.target.value);
                setData({ ...data, [field.id]: e.target.value });
              }}
            />
          </div>
        ) : field.type === 'textarea' && !field.hideIf ? (
          <div key={field.id} className='flex flex-col gap-1'>
            <span className='text-xs lg:text-sm'>
              {field.label}
              <MandatoryIndicator isMandatory={field.isMandatory} />
            </span>
            <textarea
              className='relative h-24 w-full resize-none rounded-md bg-background-tertiary p-2 text-xs placeholder:text-xs lg:text-sm lg:placeholder:text-sm'
              placeholder={field.placeholder}
              value={field.value}
              onChange={(e) => {
                field.setValue(e.target.value);
                setData({ ...data, [field.id]: e.target.value });
              }}
            />
          </div>
        ) : field.type === 'select' && !field.hideIf ? (
          <div key={field.id} className='flex flex-col gap-1'>
            <span className='text-xs lg:text-sm'>
              {field.label}
              <MandatoryIndicator isMandatory={field.isMandatory} />
            </span>
            <select
              className='relative w-full rounded-md bg-background-tertiary p-2 text-xs lg:text-sm'
              value={field.value}
              onChange={(e) => {
                field.setValue(e.target.value);
                setData({ ...data, [field.id]: e.target.value });
              }}
            >
              {field.options?.map((option) => (
                <option key={option.value} value={option.value}>
                  {option.label}
                </option>
              ))}
            </select>
          </div>
        ) : null
      )}
    </section>
  );
};
const SimpleTextInput = ({ data, setData }: SimpleTextInputProps) => {
  return (
    <section className='flex flex-col gap-4 text-xs text-secondary lg:text-sm'>
      <div className='cursor-default rounded-md bg-background-tertiary p-4'>
        <span>Consider sharing:</span>
        <ul className='ml-4 list-outside list-disc'>
          <li>What would you like to see improved or added?</li>
          <li>What did you love about your experience?</li>
          <li>
            {`What's the most interesting thing you've used Suno for or
            seen others do?`}
          </li>
        </ul>
      </div>
      <div className='flex flex-col gap-2 text-xs lg:text-sm'>
        <span>
          Your Feedback
          <MandatoryIndicator />
        </span>

        <textarea
          className='relative h-24 w-full resize-none rounded-md bg-background-tertiary p-2'
          value={data.feedback}
          onChange={(e) => setData({ ...data, feedback: e.target.value })}
        />
      </div>
    </section>
  );
};

const BillingIssue = () => {
  return (
    <section className='flex flex-col gap-4 text-xs text-foreground-secondary lg:text-sm'>
      <div className='rounded-md bg-background-tertiary p-4'>
        <span>
          For account or billing issues, please email{' '}
          <Link
            href='mailto:support@suno.com'
            className='text-primary underline'
          >
            support@suno.com
          </Link>
        </span>
      </div>
    </section>
  );
};

const TesterApplication = () => {
  return (
    <section className='flex flex-col gap-4 text-xs text-foreground-secondary lg:text-sm'>
      <div className='rounded-md bg-background-tertiary p-4'>
        <span>
          We're looking for early testers! Please fill out the{' '}
          <Link
            href={FEEDBACK_TESTER_APPLICATION_URL}
            className='text-primary underline'
          >
            form here
          </Link>{' '}
          to apply.
        </span>
      </div>
    </section>
  );
};

const FeedbackInput = ({ feedbackOption, ...rest }: FeedbackInputProps) => {
  switch (feedbackOption) {
    case FEEDBACK_OPTIONS.BUG_REPORT:
      return <BugReportInput {...rest} />;
    case FEEDBACK_OPTIONS.IDEAS:
      return <SimpleTextInput {...rest} />;
    case FEEDBACK_OPTIONS.BILLING:
      return <BillingIssue />;
    case FEEDBACK_OPTIONS.TESTER:
      return <TesterApplication />;
    default:
      return null;
  }
};

const FeedbackForm: React.FC<FeedbackFormProps> = observer(
  ({ onClose }: FeedbackFormProps) => {
    const apiClient = useApiClient();
    const { session } = useStores();
    const [feedbackOption, setFeedbackOption] = useState<number>(
      FEEDBACK_OPTIONS.RESET
    );
    const submittableOption =
      feedbackOption == FEEDBACK_OPTIONS.BUG_REPORT ||
      feedbackOption == FEEDBACK_OPTIONS.IDEAS;
    const [data, setData] = useState({
      rating: 0,
      feedback: '',
      mediaLink: '',
      platform: Platform.WEB,
      browser: '',
      link: '',
      stepsToReproduce: '',
    });
    const [canSubmit, setCanSubmit] = useState(false);
    const [isLoading, setIsLoading] = useState(false);

    const resetStates = () => {
      setData({
        rating: 0,
        feedback: '',
        mediaLink: '',
        platform: Platform.WEB,
        browser: '',
        link: '',
        stepsToReproduce: '',
      });
      setIsLoading(false);
      setCanSubmit(false);
    };

    useEffect(() => {
      // resets state when feedback option changes
      resetStates();
    }, [feedbackOption]);

    useEffect(() => {
      // reset state if closed
      resetStates();
      setFeedbackOption(FEEDBACK_OPTIONS.RESET);
    }, []);

    const isWebPlatform = (platform: Platform) => {
      return [Platform.WEB, Platform.MOBILE_WEB].includes(platform);
    };

    useEffect(() => {
      const nonEmptyRating = data.rating > 0;
      if (feedbackOption === FEEDBACK_OPTIONS.BUG_REPORT) {
        // either doesn't need browser (app) or has browser (web/mobile web)
        const validBrowser =
          !isWebPlatform(data.platform) || data.browser.length > 0;
        const validReproSteps = data.stepsToReproduce.length > 0;
        const sunoLinkRegex = /^(https?:\/\/)?(www\.)?suno\.com(?:\/.*)?$/;
        // we don't need to check link for mobile platforms
        // isWebPlatform returns true for web platforms
        const validLink = isWebPlatform(data.platform)
          ? sunoLinkRegex.test(data.link)
          : true;

        setCanSubmit(
          nonEmptyRating && validBrowser && validReproSteps && validLink
        );
      } else if (feedbackOption === FEEDBACK_OPTIONS.IDEAS) {
        const nonEmptyFeedback = data.feedback.length > 0;
        setCanSubmit(nonEmptyRating && nonEmptyFeedback);
      }
    }, [feedbackOption, data]);

    const submitFeedback = async (data: FeedbackFormData) => {
      const res = await apiClient.POST('/api/feedback/', {
        body: {
          email: session?.user?.email,
          rating: data.rating,
          feedback: data.feedback,
          mediaLink: data.mediaLink,
          platform: data.platform,
          browser: data.browser,
          link: data.link,
          stepsToReproduce: data.stepsToReproduce,
          feedbackOption: feedbackOption as Exclude<
            FeedbackOption,
            | FeedbackOption.RESET
            | FeedbackOption.BILLING
            | FeedbackOption.TESTER
          >,
        },
      });
      if (res.response.status !== 200) {
        throw new Error(res.response.statusText);
      }
      return res;
    };

    const submitFeedbackMutation = useMutation({
      mutationFn: submitFeedback,
      onSuccess: () => {
        onClose();
        setIsLoading(false);
        toast({
          duration: 3000,
          isClosable: true,
          position: 'bottom',
          title: 'Feedback submitted successfully',
          status: 'success',
        });
      },
      onError: (error: any) => {
        onClose();
        setIsLoading(false);
        toast({
          duration: 3000,
          isClosable: true,
          position: 'bottom',
          title: `Error submitting feedback${
            error.message ? `: ${error.message}` : ''
          }`,
          status: 'error',
        });
      },
    });

    const handleSubmit = useMemo(
      () => async () => {
        setIsLoading(true);
        if (!session?.user?.email) {
          toast({
            duration: 3000,
            isClosable: true,
            position: 'bottom',
            title: 'You must be logged in to submit feedback',
            status: 'error',
          });
          return setIsLoading(false);
        }

        await submitFeedbackMutation.mutateAsync(data);
      },
      [data, session?.user?.email]
    );

    return (
      <Modal
        title='Share Your Feedback'
        onClose={onClose}
        wrapperClasses='max-h-[480px] flex flex-col gap-4 overflow-y-auto pb-6'
        withHorizontalPadding
      >
        <div className='flex flex-col gap-8'>
          <FeedbackOptions
            feedbackOption={feedbackOption}
            setFeedbackOption={setFeedbackOption}
          />
          {submittableOption && <Ratings data={data} setData={setData} />}
          <FeedbackInput
            feedbackOption={feedbackOption}
            data={data}
            setData={setData}
          />
        </div>

        {submittableOption && (
          <Button disabled={!canSubmit || isLoading} onClick={handleSubmit}>
            Submit
          </Button>
        )}
      </Modal>
    );
  }
);

export default FeedbackForm;
