import { BodyText, Card } from 'src/components/ui'
import type { Visibility } from 'src/lib/api-types'
import { YStack } from 'tamagui'

// Compose Redesign Phase 1 §3.6: replaces the hardcoded six-string
// `warningFor()` table with a small composer that builds the banner from
// orthogonal post-state inputs. Each input contributes at most one line;
// the banner renders as a single `<Card tone="bordered">` block with the
// lines stacked. The signature is intentionally extension-friendly — Phase
// 5's alt-text-required and quote-is-private banners reuse the same shape
// and only need to flip their input flag at the call site.

export type BannerTone = 'info' | 'warning' | 'danger'

export type BannerInputs = {
  scope: Visibility
  sensitive: boolean
  /** True for private accounts — coerces every post to followers-only. */
  locked: boolean
  /** Phase 3 §3.6: account-level "always require CW" preference
   * (`verify_credentials.source.sensitive`). Pixelfed's `profile.cw=true`
   * accounts forces every post to `sensitive=true` server-side
   * (`ApiV1Controller.php:3810`); Mastodon's "Always mark media as sensitive"
   * preference does the same. We surface the coercion in copy when set. */
  alwaysCw?: boolean
  /** Phase 3 §3.6: account-level default privacy is `unlisted`. Pixelfed
   * coerces `public → unlisted` for these accounts
   * (`ApiV1Controller.php:3798-3802`). Detected client-side from
   * `verify_credentials.source.privacy === 'unlisted'`. The banner only
   * fires when the user has picked `public`, since on `unlisted` they're
   * already aligned with the server's default. */
  unlistedDefault?: boolean
  /** Phase 5: the user has enabled "Require alt text" in Settings →
   * Accessibility. Reads `appStorage.getBoolean(uiKeys.requireSelfAltText)`
   * — this is a device pref, not a server-side gate. The banner only
   * fires when this is on AND `hasMissingAlt`. */
  requiresAlt?: boolean
  /** Phase 5: at least one attached media item has empty alt text. */
  hasMissingAlt?: boolean
  /** Phase 5: the post being quoted has private visibility. */
  quoteIsPrivate?: boolean
}

export type BannerResult = {
  tone: BannerTone
  lines: string[]
}

export function buildBanner(inputs: BannerInputs): BannerResult {
  const {
    scope,
    sensitive,
    locked,
    alwaysCw = false,
    unlistedDefault = false,
    requiresAlt = false,
    hasMissingAlt = false,
    quoteIsPrivate = false,
  } = inputs

  const lines: string[] = []
  if (scope === 'private' || locked) {
    lines.push('Only your followers can see this.')
  } else if (scope === 'unlisted') {
    lines.push("Won't appear on public timelines.")
  } else if (unlistedDefault && scope === 'public') {
    // Server will silently coerce `public → unlisted` for accounts whose
    // default privacy is `unlisted`. Tell the user before submit so the
    // outcome matches their expectation.
    lines.push('Your account auto-unlists public posts.')
  }
  if (alwaysCw) {
    // The sensitive flag is coerced server-side regardless of the toggle's
    // state, so this line is unconditional on `alwaysCw` — telling the
    // user "media will be hidden" alongside it would be redundant.
    lines.push('Your account is set to always require a content warning.')
  } else if (sensitive) {
    lines.push('Media will be hidden until tapped.')
  }
  if (requiresAlt && hasMissingAlt) {
    // Copy mirrors the existing pre-submit toast in `useComposer.handlePost`
    // ("You have enabled the requirement for alt text, …") — the source is
    // the user's own Settings → Accessibility toggle, not server policy, so
    // attributing it to "your instance" would mislead.
    lines.push('You require alt text — some media is missing a description.')
  }
  if (quoteIsPrivate) {
    lines.push(
      "This is a private post — only the author's followers will see your quote."
    )
  }

  const tone: BannerTone = requiresAlt && hasMissingAlt ? 'danger' : 'info'
  return { tone, lines }
}

type Props = {
  inputs: BannerInputs
}

export function ComposerBanner({ inputs }: Props) {
  const { tone, lines } = buildBanner(inputs)
  if (lines.length === 0) return null
  return (
    <Card
      tone="bordered"
      mt="$2"
      borderColor={tone === 'danger' ? '$colorDanger' : '$borderColor'}
    >
      <YStack gap="$1">
        {lines.map((line) => (
          <BodyText
            key={line}
            tone={tone === 'danger' ? 'danger' : 'secondary'}
            emphasis="medium"
          >
            {line}
          </BodyText>
        ))}
      </YStack>
    </Card>
  )
}
