"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/Button";
import { OAuthAccountSelection } from "@/components/dashboard/OAuthAccountSelection";
import { DashboardPageContainer } from "@/components/dashboard/DashboardPageContainer";
import {
  ConnectedSocialAccountCard,
  DisconnectConfirmDialog,
  ViewProfileLink,
} from "@/components/dashboard/SocialAccountUi";
import { DashboardShell } from "@/components/dashboard/DashboardShell";
import { SocialProviderIcon } from "@/components/dashboard/SocialProviderIcon";
import { useSocialAccountData } from "@/components/dashboard/useSocialAccountData";
import { useSocialAccounts } from "@/components/dashboard/useSocialAccounts";
import { EmptyState } from "@/components/ui/EmptyState";
import { ErrorState } from "@/components/ui/ErrorState";
import { PageHeader, SectionHeader } from "@/components/ui/PageHeader";
import { AccountListSkeleton, PlatformCardSkeleton } from "@/components/ui/Skeleton";
import { StatusBadge } from "@/components/ui/StatusBadge";
import { SocialOAuthDisclosure } from "@/components/legal/SocialOAuthDisclosure";
import { ApiError, ensureCsrfCookie, socialAccountDataApi, socialAccountsApi } from "@/lib/api";
import {
  analyticsAccountSyncControl,
  providerSupportsOAuthReconnect,
  reconnectActionLabel,
  socialAccountNeedsReconnect,
  syncNeedsReconnect,
} from "@/lib/social-auth-failure";
import {
  buildSocialAccountCardViewModel,
  dataAccountForId,
} from "@/lib/social-account-card-metrics";
import {
  isEmptySocialOAuthReturn,
  oauthReconnectFollowUp,
  parseSocialOAuthReturnSearch,
  reconnectSyncingMessage,
  shouldKeepReconnectedSyncingState,
  shouldTriggerExistingSyncRefresh,
} from "@/lib/social-oauth-return";
import {
  SOCIAL_PROVIDERS,
  accountForProvider,
  isProviderConnectable,
  socialProviderLabel,
} from "@/lib/social-providers";
import type { User } from "@/types/auth";
import type { SocialAccount } from "@/types/social-account";

function ConnectComingSoonButton() {
  return (
    <Button type="button" variant="secondary" size="sm" className="w-full cursor-not-allowed opacity-70 sm:w-auto" disabled>
      Coming soon
    </Button>
  );
}

function ConnectProviderButton({
  connecting,
  onConnect,
}: {
  label: string;
  connecting: boolean;
  onConnect: () => void;
}) {
  return (
    <Button type="button" size="sm" className="w-full sm:w-auto" disabled={connecting} aria-busy={connecting} onClick={onConnect}>
      {connecting ? "Connecting…" : "Connect"}
    </Button>
  );
}

function PlatformCard({
  providerKey,
  account,
  connectable,
  connecting,
  disconnectingId,
  onConnect,
  onDisconnect,
}: {
  providerKey: string;
  account: SocialAccount | undefined;
  connectable: boolean;
  connecting: boolean;
  disconnectingId: number | null;
  onConnect: () => void;
  onDisconnect: (account: SocialAccount) => void;
}) {
  const config = SOCIAL_PROVIDERS.find((item) => item.key === providerKey);
  const label = config?.label ?? socialProviderLabel(providerKey);
  const connected = Boolean(account);
  const needsReconnect = account ? socialAccountNeedsReconnect(account) : false;
  const canReconnect = providerSupportsOAuthReconnect(providerKey) && connectable;

  return (
    <div className="flex h-full flex-col rounded-pv border border-line bg-surface p-3">
      <div className="flex min-w-0 items-center gap-2.5">
        <span className="inline-flex size-9 shrink-0 items-center justify-center rounded-full bg-bg text-primary">
          <SocialProviderIcon provider={providerKey} />
        </span>
        <div className="min-w-0 flex-1">
          <h3 className="text-[0.8125rem] font-semibold text-primary">{label}</h3>
          <div className="mt-1">
            {connected && needsReconnect ? (
              <StatusBadge variant="warning">Reconnect required</StatusBadge>
            ) : connected ? (
              <StatusBadge variant="success">Connected</StatusBadge>
            ) : connectable ? (
              <StatusBadge variant="neutral">Not connected</StatusBadge>
            ) : (
              <StatusBadge variant="neutral">Coming soon</StatusBadge>
            )}
          </div>
        </div>
      </div>
      <div className="mt-3 flex flex-col gap-2 sm:flex-row">
        {account ? (
          <>
            {account.profile_url ? <ViewProfileLink href={account.profile_url} compact /> : null}
            {needsReconnect && canReconnect ? (
              <Button
                type="button"
                size="sm"
                className="w-full sm:w-auto"
                disabled={connecting}
                aria-busy={connecting}
                aria-label={reconnectActionLabel(providerKey)}
                onClick={onConnect}
              >
                {connecting ? "Redirecting…" : reconnectActionLabel(providerKey)}
              </Button>
            ) : null}
            <Button
              type="button"
              variant="secondary"
              size="sm"
              className="w-full sm:w-auto"
              disabled={disconnectingId === account.id}
              onClick={() => onDisconnect(account)}
            >
              {disconnectingId === account.id ? "Disconnecting…" : "Disconnect"}
            </Button>
          </>
        ) : connectable ? (
          <ConnectProviderButton label={label} connecting={connecting} onConnect={onConnect} />
        ) : (
          <ConnectComingSoonButton />
        )}
      </div>
    </div>
  );
}

function notifyOAuthReturnError(error: string): void {
  if (error.endsWith("_cancelled")) {
    const provider = error.slice(0, -"_cancelled".length);
    toast.error(`${socialProviderLabel(provider)} connection was cancelled.`);
    return;
  }

  const provider = error.endsWith("_failed") ? error.slice(0, -"_failed".length) : null;
  toast.error(
    provider
      ? `Unable to connect ${socialProviderLabel(provider)}. Please try again.`
      : "Unable to connect that social account. Please try again.",
  );
}

function syncButtonLabel(kind: string, label: string): string {
  if (kind === "refresh") {
    return "Sync";
  }
  if (kind === "syncing") {
    return "Syncing…";
  }
  return label;
}

function SocialAccountsContent({ user }: { user: User }) {
  const {
    accounts,
    connectableProviders,
    isLoading,
    error,
    retry,
    removeAccount,
  } = useSocialAccounts();
  const {
    dashboard,
    syncingId,
    refreshAccount,
    retry: retryDashboard,
  } = useSocialAccountData();
  const [pending, setPending] = useState<SocialAccount | null>(null);
  const [disconnectingId, setDisconnectingId] = useState<number | null>(null);
  const [connectingProvider, setConnectingProvider] = useState<string | null>(null);
  const [oauthSelection, setOauthSelection] = useState<{ provider: string; token: string } | null>(null);
  const [postReconnectProvider, setPostReconnectProvider] = useState<string | null>(null);
  const syncRefreshTriggeredRef = useRef(false);
  const reconnectReloadStartedRef = useRef(false);

  const reloadAll = useCallback(() => {
    retry();
    retryDashboard();
  }, [retry, retryDashboard]);

  useEffect(() => {
    let cancelled = false;

    void (async () => {
      const oauthReturn = parseSocialOAuthReturnSearch(window.location.search);

      if (isEmptySocialOAuthReturn(oauthReturn)) {
        return;
      }

      window.history.replaceState(window.history.state, "", window.location.pathname);

      const followUp = oauthReconnectFollowUp(oauthReturn);

      if (oauthReturn.selection) {
        if (!cancelled) {
          setOauthSelection(oauthReturn.selection);
        }
        return;
      }

      if (oauthReturn.error) {
        notifyOAuthReturnError(oauthReturn.error);
      }

      if (followUp.showReconnectedSyncing && followUp.reconnectedProvider) {
        syncRefreshTriggeredRef.current = false;
        reconnectReloadStartedRef.current = false;
        if (!cancelled) {
          setPostReconnectProvider(followUp.reconnectedProvider);
        }
      }

      if (!followUp.reloadAccounts) {
        return;
      }

      try {
        await ensureCsrfCookie();
      } catch {
        if (!cancelled) {
          toast.error("Your session has expired. Please sign in again.");
        }
        return;
      }

      if (!cancelled) {
        reloadAll();
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [reloadAll]);

  useEffect(() => {
    if (!postReconnectProvider) {
      return;
    }

    if (isLoading) {
      reconnectReloadStartedRef.current = true;
      return;
    }

    if (!reconnectReloadStartedRef.current) {
      return;
    }

    const account = accounts.find((item) => item.provider === postReconnectProvider);

    if (!account || socialAccountNeedsReconnect(account)) {
      setPostReconnectProvider(null);
      return;
    }

    if (!syncRefreshTriggeredRef.current && shouldTriggerExistingSyncRefresh(account)) {
      syncRefreshTriggeredRef.current = true;
      void socialAccountDataApi
        .sync(account.id)
        .catch(() => undefined)
        .finally(() => {
          reloadAll();
        });
      return;
    }

    // Pending sync is shown via sync_status + list polling — drop the temporary
    // post-reconnect overlay so "Syncing" cannot stick after the job finishes.
    if (
      account.sync_status === "pending" ||
      account.sync_status === "success" ||
      account.sync_status === "failed" ||
      !shouldKeepReconnectedSyncingState(account)
    ) {
      setPostReconnectProvider(null);
    }
  }, [accounts, isLoading, postReconnectProvider, reloadAll]);

  const handleConnect = useCallback(
    (provider: string) => {
      if (connectingProvider !== null) {
        return;
      }

      setConnectingProvider(provider);
      window.location.assign(socialAccountsApi.connectStartUrl(provider));
    },
    [connectingProvider],
  );

  const handleSync = useCallback(
    (account: SocialAccount) => {
      const dataAccount = dataAccountForId(dashboard?.accounts, account.id);
      if (syncNeedsReconnect(dataAccount?.sync) || socialAccountNeedsReconnect(account)) {
        return;
      }
      void refreshAccount(account.id).then(() => {
        retry();
      });
    },
    [dashboard?.accounts, refreshAccount, retry],
  );

  const handleConfirmDisconnect = useCallback(async () => {
    if (!pending || disconnectingId !== null) {
      return;
    }

    const account = pending;
    setDisconnectingId(account.id);

    try {
      await ensureCsrfCookie();
      await socialAccountsApi.delete(account.id);
      removeAccount(account.id);
      setPending(null);
      retryDashboard();
      toast.success(`${socialProviderLabel(account.provider)} disconnected.`);
    } catch (caught) {
      if (caught instanceof ApiError && caught.status === 403) {
        toast.error("You don't have permission to disconnect that account.");
      } else if (caught instanceof ApiError && (caught.status === 401 || caught.status === 419)) {
        toast.error(caught.message || "Your session has expired. Please sign in again.");
      } else {
        toast.error("Unable to disconnect that account. Please try again.");
      }
    } finally {
      setDisconnectingId(null);
    }
  }, [pending, disconnectingId, removeAccount, retryDashboard]);

  const extraConnected = accounts.filter(
    (account) => !SOCIAL_PROVIDERS.some((provider) => provider.key === account.provider),
  );

  return (
    <DashboardPageContainer>
      {oauthSelection ? (
        <OAuthAccountSelection
          provider={oauthSelection.provider}
          selectionToken={oauthSelection.token}
          onComplete={() => {
            setOauthSelection(null);
            reloadAll();
          }}
          onCancel={() => setOauthSelection(null)}
        />
      ) : (
        <>
          <PageHeader description="Connect and manage your social platforms." />
          <SocialOAuthDisclosure className="mb-6 rounded-pv border border-line bg-bg px-4 py-3" />

          {user.account_type !== "creator" && !isLoading && error ? (
            <ErrorState title="Social accounts unavailable" message={error} />
          ) : null}

          {user.account_type === "creator" ? (
            <>
              <section aria-labelledby="available-platforms-heading">
                <SectionHeader
                  id="available-platforms-heading"
                  title="Available platforms"
                  className="mb-3"
                />

                {isLoading ? (
                  <PlatformCardSkeleton count={4} />
                ) : (
                  <div className="grid grid-cols-2 gap-3 md:grid-cols-4">
                    {SOCIAL_PROVIDERS.map((provider) => (
                      <PlatformCard
                        key={provider.key}
                        providerKey={provider.key}
                        account={error ? undefined : accountForProvider(accounts, provider.key)}
                        connectable={!error && isProviderConnectable(provider.key, connectableProviders)}
                        connecting={connectingProvider === provider.key}
                        disconnectingId={disconnectingId}
                        onConnect={() => handleConnect(provider.key)}
                        onDisconnect={setPending}
                      />
                    ))}
                    {!error
                      ? extraConnected.map((account) => (
                          <PlatformCard
                            key={account.id}
                            providerKey={account.provider}
                            account={account}
                            connectable={false}
                            connecting={false}
                            disconnectingId={disconnectingId}
                            onConnect={() => undefined}
                            onDisconnect={setPending}
                          />
                        ))
                      : null}
                  </div>
                )}
              </section>

              <section aria-labelledby="connected-accounts-heading" className="mt-8">
                <SectionHeader id="connected-accounts-heading" title="Connected accounts" className="mb-3" />

                {postReconnectProvider ? (
                  <p className="mb-3 text-[0.8125rem] text-ink-60" role="status">
                    {reconnectSyncingMessage(postReconnectProvider)}
                  </p>
                ) : null}

                {isLoading ? <AccountListSkeleton rows={2} /> : null}

                {!isLoading && error ? (
                  <ErrorState title="Unable to load social accounts" message={error} onRetry={reloadAll} />
                ) : null}

                {!isLoading && !error && accounts.length === 0 ? (
                  <EmptyState
                    title="No social accounts connected"
                    description="Connect a platform above to link your profiles."
                    action={
                      <Button href="#available-platforms-heading" size="sm" variant="secondary">
                        Browse platforms
                      </Button>
                    }
                  />
                ) : null}

                {!isLoading && !error && accounts.length > 0 ? (
                  <ul className="space-y-3">
                    {accounts.map((account) => {
                      const needsReconnect = socialAccountNeedsReconnect(account);
                      const canReconnect =
                        providerSupportsOAuthReconnect(account.provider) &&
                        isProviderConnectable(account.provider, connectableProviders);
                      const postReconnectSyncing =
                        postReconnectProvider === account.provider &&
                        shouldKeepReconnectedSyncingState(account);
                      const dataAccount = dataAccountForId(dashboard?.accounts, account.id);
                      const metrics = buildSocialAccountCardViewModel(account, dataAccount);
                      const syncControl = analyticsAccountSyncControl(
                        dataAccount?.sync ?? {
                          status: account.sync_status,
                          failure_code: account.sync_failure_code,
                        },
                        {
                          isSubmitting: syncingId === account.id,
                          provider: account.provider,
                        },
                      );
                      const syncDisabled =
                        needsReconnect ||
                        account.sync_status === "pending" ||
                        syncingId === account.id ||
                        !syncControl.actionable ||
                        syncControl.kind === "reconnect";

                      return (
                        <li key={account.id}>
                          <ConnectedSocialAccountCard
                            account={account}
                            metrics={metrics}
                            postReconnectSyncing={postReconnectSyncing}
                            actions={
                              <>
                                {needsReconnect && canReconnect ? (
                                  <Button
                                    type="button"
                                    size="sm"
                                    disabled={connectingProvider === account.provider}
                                    aria-busy={connectingProvider === account.provider}
                                    aria-label={reconnectActionLabel(account.provider)}
                                    onClick={() => handleConnect(account.provider)}
                                  >
                                    {connectingProvider === account.provider
                                      ? "Redirecting…"
                                      : reconnectActionLabel(account.provider)}
                                  </Button>
                                ) : (
                                  <Button
                                    type="button"
                                    variant="secondary"
                                    size="sm"
                                    disabled={syncDisabled}
                                    aria-busy={
                                      syncControl.kind === "syncing" || syncingId === account.id
                                    }
                                    aria-label={`Sync ${socialProviderLabel(account.provider)}`}
                                    onClick={() => handleSync(account)}
                                  >
                                    {syncButtonLabel(syncControl.kind, syncControl.label)}
                                  </Button>
                                )}
                                <Button
                                  type="button"
                                  variant="secondary"
                                  size="sm"
                                  disabled={disconnectingId === account.id}
                                  onClick={() => setPending(account)}
                                >
                                  {disconnectingId === account.id ? "Disconnecting…" : "Disconnect"}
                                </Button>
                              </>
                            }
                          />
                        </li>
                      );
                    })}
                  </ul>
                ) : null}
              </section>
            </>
          ) : null}

          {pending ? (
            <DisconnectConfirmDialog
              providerLabel={socialProviderLabel(pending.provider)}
              busy={disconnectingId === pending.id}
              onCancel={() => {
                if (disconnectingId === null) {
                  setPending(null);
                }
              }}
              onConfirm={() => {
                void handleConfirmDisconnect();
              }}
            />
          ) : null}
        </>
      )}
    </DashboardPageContainer>
  );
}

const CREATOR_ONLY = ["creator"] as const;

export function DashboardSocialAccountsPage() {
  return (
    <DashboardShell title="Social Accounts" allowedAccountTypes={CREATOR_ONLY}>
      {(user) => <SocialAccountsContent user={user} />}
    </DashboardShell>
  );
}
