import clsx from "clsx";
import { useState } from "react";
import { ActionFunctionArgs, redirect } from "react-router-dom";
import { PAYSITE_LIST, SITE_NAME } from "#env/env-vars";
import { createImporterStatusPageURL } from "#lib/urls";
import { fetchCreateImport } from "#api/imports";
import { useClient } from "#hooks";
import { PageSkeleton } from "#components/pages";
import { FormRouter, FormSection } from "#components/forms";
import { paysites } from "#entities/paysites";
import { isRegisteredAccount } from "#entities/account";

const dmLookup = ["patreon", "fansly"];

/**
 * TODO: split into separate pages per service
 */
export function ImporterPage() {
  const isClient = useClient();
  const [selectedService, changeSelectedService] = useState(PAYSITE_LIST[0]);
  const title = "Import paywall posts/comments/DMs";
  const heading = "Import from Paysite";

  return (
    <PageSkeleton name="importer" title={title} heading={heading}>
      <FormRouter
        id="import-list"
        className="form form--bigger"
        method="POST"
        submitButton={(state) => "Submit key"}
      >
        <div className="form__section">
          <label htmlFor="service" className="form__label">
            Paysite:
          </label>
          <select
            id="service"
            className="form__select"
            name="service"
            defaultValue={PAYSITE_LIST[0]}
            onChange={(event) => changeSelectedService(event.target.value)}
          >
            {PAYSITE_LIST.map((entry, index) => {
              const paySite = paysites[entry];

              return (
                <option key={index} className="form__option" value={entry}>
                  {paySite.title}
                </option>
              );
            })}
          </select>
        </div>

        <FormSection>
          <label className="form__label" htmlFor="session-key">
            Session key:
          </label>
          <input
            id="session-key"
            className="form__input"
            type="text"
            name="session_key"
            autoComplete="off"
            autoCorrect="off"
            autoCapitalize="off"
            spellCheck="false"
            maxLength={1024}
            required
          />

          <small className="form__subtitle other__notes">
            <a href="/importer/tutorial">Learn how to get your session key.</a>
          </small>

          <small
            className="form__subtitle fansly__notes"
            hidden={selectedService !== "fansly" ? true : false}
          >
            Session key.
            <br />
            On desktop/mobile right click copy the link of this URL:
            <br />
            <pre>{`javascript:prompt('Fansly Token', btoa(JSON.stringify({...JSON.parse(localStorage?.session_active_session),device:localStorage?.device_device_id})))`}</pre>
            then on the Fansly webpage enter{" "}
            <span style={{ color: "white", fontWeight: "bold" }}>
              javascript:
            </span>{" "}
            into your browser url bar and then paste the previously copied
            string. This will output a result that is your session key
            <br />
            <br />
            Alternative method: <br />
            Copy the code string below and post this into the browser console.
            (Open with keyboard F12 or right click {">"} Inspect Element)
            <br />
            Code:{" "}
            <code
              style={{ color: "#b5b5b5", userSelect: "all" }}
            >{`btoa(JSON.stringify({...JSON.parse(localStorage?.session_active_session||'{}'),device:localStorage?.device_device_id}))`}</code>
          </small>

          <small
            className="form__subtitle onlyfans__notes"
            hidden={selectedService !== "onlyfans"}
          >
            Session key. Can be found in Cookies -{">"} sess.
          </small>

          <small
            className="form__subtitle fanbox__notes"
            hidden={selectedService !== "fanbox"}
          >
            On Fanbox page, Press F12 -{">"} "Application" tab (check {">"}
            {">"} if its hidden) -{">"} Storage: Cookies -{">"} fanbox.cc -{">"}{" "}
            FANBOXSESSID value <br />{" "}
            <a href="/importer/tutorial_fanbox">
              Detailed steps in how to get your fanbox session ID.
            </a>
          </small>

          <small
            className="form__subtitle candfans__notes"
            hidden={selectedService !== "candfans"}
          >
            On CandFans page, Press F12 -{">"} "Application" tab (check {">"}
            {">"} if its hidden) -{">"} Storage: Cookies -{">"} candfans.jp -
            {">"} secure_candfans_session value. <br />{" "}
            <a href="/importer/tutorial">Detailed steps.</a>{" "}
          </small>
        </FormSection>

        {selectedService !== "onlyfans" ? undefined : (
          <div id="onlyfans-section">
            <div className="form__section">
              <input
                id="auth-id"
                className="form__input"
                type="text"
                name="auth_id"
                placeholder="User ID"
                autoComplete="off"
                autoCorrect="off"
                autoCapitalize="off"
                spellCheck="false"
                maxLength={1024}
                pattern="[0-9]{3,12}"
                required
              />
              <small className="form__subtitle">
                Your user ID. Can be found in Cookies -{">"} auth_id.
              </small>
            </div>

            <div className="form__section">
              <input
                id="x-bc"
                className="form__input"
                type="text"
                name="x-bc"
                placeholder="BC Token"
                autoComplete="off"
                autoCorrect="off"
                autoCapitalize="off"
                spellCheck="false"
                maxLength={1024}
                pattern="[0-9a-f]{18,50}"
                required
              />
              <small className="form__subtitle">
                BC token. Can be found in Local Storage -{">"} bcTokenSha, or
                the headers of an XHR request -{">"} x-bc.
                <br />
                Paste this on the console{" "}
                <code style={{ color: "#b5b5b5", userSelect: "all" }}>
                  localStorage.bcTokenSha
                </code>
              </small>
            </div>

            <div className="form__section">
              <label htmlFor="user-agent" className="form__label">
                User Agent:
              </label>
              <input
                id="user-agent"
                className="form__input"
                type="text"
                name="user_agent"
                placeholder="User Agent"
                autoComplete="off"
                autoCorrect="off"
                autoCapitalize="off"
                spellCheck="false"
                minLength={10}
                maxLength={1024}
                required
                defaultValue={!isClient ? undefined : navigator.userAgent}
              />
              <small className="form__subtitle">
                This needs to be set to the{" "}
                <a
                  href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent"
                  target="_blank"
                >
                  User-Agent
                </a>
                of the last device that logged into your OnlyFans account; leave
                it as the default value if you are on it right now.
              </small>
            </div>
          </div>
        )}

        <div
          id="discord-section"
          className={clsx(
            "form__section",
            selectedService !== "discord" && "form__section--hidden"
          )}
        >
          <label htmlFor="channel_ids" className="form__label">
            Discord channel IDs:
          </label>
          <input
            type="text"
            className="form__input"
            id="channel_ids"
            name="channel_ids"
            autoComplete="off"
            autoCorrect="off"
            autoCapitalize="off"
            spellCheck="false"
          />
          <small className="form__subtitle">comma separated, no spaces</small>
        </div>

        <div id="consent" className="form__section form__section--checkbox">
          <input
            className="form__input"
            type="checkbox"
            defaultChecked={true}
            id="save-session-key"
            name="save_session_key"
            value="1"
          />
          <label className="form__label" htmlFor="save-session-key">
            Allow administrator to use my session for debugging
            <br />
            <small className="form__subtitle">
              Contributed debugging keys are encrypted using a strong RSA 4096
              key that only the administrator can decipher.
            </small>
          </label>
        </div>

        <div
          id="auto-import-consent"
          className="form__section form__section--checkbox"
        >
          <input
            className="form__input"
            type="checkbox"
            defaultChecked={true}
            id="auto_import"
            name="auto_import"
            value="1"
          />
          <label className="form__label" htmlFor="auto_import">
            Allow the importer to save my session key for auto-import
            <br />
            <small className="form__subtitle">
              If enabled, new posts will automatically be imported every 24
              hours without manual intervention. Direct message importing still
              requires manual import. See notes below for security information.
            </small>
          </label>
        </div>

        <div
          id="dm-consent"
          className={clsx(
            "form__section",
            "form__section--checkbox",
            !dmLookup.includes(selectedService) && "form__section--hidden"
          )}
        >
          <input
            className="form__input"
            type="checkbox"
            id="save-dms"
            name="save_dms"
            value="1"
            defaultChecked={dmLookup.includes(selectedService)}
          />
          <label className="form__label" htmlFor="save-dms">
            Allow the importer to access your direct messages
            <br />
            <small className="form__subtitle">
              You will be able to manually approve or discard messages before
              they are publicly displayed.
            </small>
          </label>
        </div>

        <div
          id="fanbox-test-consent"
          className={clsx(
            "form__section",
            "form__section--checkbox",
            selectedService !== "fanbox" && "form__section--hidden"
          )}
        >
          <input
            className="form__input"
            type="checkbox"
            id="fanbox-test-consent"
            name="fanbox-test-consent"
            defaultChecked={false}
            value="1"
          />
          <label className="form__label" htmlFor="fanbox-test-consent">
            I agree that this importer is in its testing phase, and that there
            may be risks involved.
            <br />
            <small className="form__subtitle">
              <a href="/fanboximports">Check details here</a>
            </small>
          </label>
        </div>
      </FormRouter>

      <h2 className="site-section__subheading">Important information</h2>
      <p>
        Your session key is used to scrape paid posts from your feed. After
        downloading missing posts, the key is immediately discarded and never
        stored without permission.
      </p>

      {!PAYSITE_LIST.includes("fantia") ? undefined : (
        <>
          <h3>Fantia</h3>
          <ul>
            <li>
              At least one paid content must be unlocked for the post to be
              imported. <i>Free posts cannot be archived at this time.</i>
            </li>
            <li>
              In order to download post contents accurately, the importer will
              automatically enable adult-viewing mode for duration of the import
              if you have it turned off.{" "}
              <b>Do not change back to general-viewing during imports.</b>
            </li>
          </ul>
        </>
      )}

      <h3>Auto-import</h3>
      <p>
        The auto-import feature allows users to give {SITE_NAME} permission to
        automatically detect and retrieve new posts and creators by storing
        session keys long-term, without need for manual key submission. All keys
        are encrypted using a strong RSA 4096 key. When the administrators start
        a new autoimport round, a computer outside of {SITE_NAME}'s
        infrastucture sends the private key to the backend, allowing it to
        decrypt all working keys and start import tasks. Even if {SITE_NAME}'s
        private database were to somehow be compromised, your tokens would
        remain anonymous and secure.
        <br />
        If you are logged into {SITE_NAME}, any key you submit with autoimport
        enabled can be managed under the <b>Keys</b> section of your{" "}
        <b>[Account]</b> tab in the header. There, you will be able to view
        import logs or revoke access.{" "}
        <i>Please note that anonymously-submitted keys cannot be managed.</i>
      </p>
    </PageSkeleton>
  );
}

export async function action({ request }: ActionFunctionArgs) {
  try {
    if (request.method !== "POST") {
      throw new Error(`Unknown method "${request.method}".`);
    }

    const data = await request.formData();

    const service = (data.get("service") as string | null)?.trim();
    {
      if (!service) {
        throw new Error("Service name is required.");
      }

      if (!PAYSITE_LIST.includes(service)) {
        throw new Error(`Unknown service "${service}".`);
      }
    }

    let isDMConsentChecked: boolean | undefined = undefined;
    {
      const inputValue = (data.get("save_dms") as string | null)?.trim();

      if (inputValue === "1") {
        isDMConsentChecked = true;
      }
    }

    if (
      service === "patreon" &&
      isDMConsentChecked &&
      !(await isRegisteredAccount())
    ) {
      throw new Error("You must be registered to import DMs.");
    }

    let isFanboxConsentChecked: boolean | undefined = undefined;
    {
      const inputValue = (
        data.get("fanbox-test-consent") as string | null
      )?.trim();

      if (inputValue === "1") {
        isFanboxConsentChecked = true;
      }
    }

    if (service === "fanbox" && !isFanboxConsentChecked) {
      throw new Error("You need to agree to fanbox test imports.");
    }

    const sessionKey = (data.get("session_key") as string | null)?.trim();
    {
      if (!sessionKey) {
        throw new Error("Session key is required.");
      }
    }

    const saveSessionKey = (
      data.get("save_session_key") as string | null
    )?.trim();

    const autoImport = (data.get("auto_import") as string | null)?.trim();

    const userAgent = (data.get("user_agent") as string | null)?.trim();

    const onlyfansXBC = (data.get("x-bc") as string | null)?.trim();

    const onlyfansAuthID = (data.get("auth_id") as string | null)?.trim();

    const discordChannelIDs = (
      data.get("channel_ids") as string | null
    )?.trim();

    const { import_id } = await fetchCreateImport({
      service,
      session_key: sessionKey,
      save_session_key: saveSessionKey,
      auto_import: autoImport,
      save_dms: isDMConsentChecked,
      user_agent: userAgent,
      "x-bc": onlyfansXBC,
      auth_id: onlyfansAuthID,
      channel_ids: discordChannelIDs,
    });

    return redirect(String(createImporterStatusPageURL(import_id)));
  } catch (error) {
    return error;
  }
}
