#!/bin/bash

set -euo pipefail

ROOT_DIR="$(git rev-parse --show-toplevel)"
cd "$ROOT_DIR"

python3 - <<'PY'
from pathlib import Path
import re
import sys


def lite_active_lines(path: str) -> list[tuple[int, str]]:
    """Return source lines which can compile when KIVO_APP_STORE_LITE is true."""
    result: list[tuple[int, str]] = []
    # Each frame is the set of possible KIVO_APP_STORE_LITE values allowed by
    # that preprocessor branch. Unknown conditions permit both values.
    stack: list[set[bool]] = [{True, False}]
    for line_number, line in enumerate(Path(path).read_text().splitlines(), 1):
        stripped = line.strip()
        if re.fullmatch(r"#if\s+KIVO_APP_STORE_LITE", stripped):
            stack.append(stack[-1] & {True})
            continue
        if re.fullmatch(r"#if\s+!KIVO_APP_STORE_LITE", stripped):
            stack.append(stack[-1] & {False})
            continue
        if stripped.startswith("#if "):
            stack.append(set(stack[-1]))
            continue
        if stripped == "#else":
            if len(stack) < 2:
                raise AssertionError(f"{path}:{line_number}: unmatched #else")
            parent = stack[-2]
            stack[-1] = parent - stack[-1]
            continue
        if stripped == "#endif":
            if len(stack) < 2:
                raise AssertionError(f"{path}:{line_number}: unmatched #endif")
            stack.pop()
            continue
        if True in stack[-1]:
            result.append((line_number, line))
    if len(stack) != 1:
        raise AssertionError(f"{path}: unterminated conditional compilation block")
    return result


def require(pattern: str, path: str) -> None:
    source = Path(path).read_text()
    if re.search(pattern, source, re.MULTILINE | re.DOTALL) is None:
        raise AssertionError(f"{path}: missing required Lite guard pattern: {pattern}")


def forbid_lite(token: str, path: str) -> None:
    matches = [(line_number, line) for line_number, line in lite_active_lines(path) if token in line]
    if matches:
        formatted = ", ".join(f"{path}:{line_number}" for line_number, _ in matches)
        raise AssertionError(f"Lite-reachable token {token!r}: {formatted}")


story_manager = "SignalServiceKit/Messages/Stories/StoryManager.swift"
home_tabs = "Signal/src/ViewControllers/HomeView/HomeTabBarController.swift"
settings = "Signal/src/ViewControllers/AppSettings/AppSettingsViewController.swift"
split_view = "Signal/src/ViewControllers/HomeView/ConversationSplitViewController.swift"
avatar_view = "SignalUI/Views/ConversationAvatarView.swift"
system_story_manager = "SignalServiceKit/Messages/Stories/SystemStoryManager.swift"
notification_actions = "Signal/Notifications/NotificationActionHandler.swift"
conversation_delegate = "Signal/ConversationView/ConversationViewController+CVComponentDelegate.swift"
photo_capture = "Signal/src/ViewControllers/Photos/PhotoCaptureViewController.swift"
link_preview_attachment = "Signal/src/ViewControllers/LinkPreviewAttachmentViewController.swift"
media_controls = "Signal/src/ViewControllers/Photos/MediaControls.swift"
notification_presenter = "SignalServiceKit/Notifications/NotificationPresenterImpl.swift"

# Core state is compile-time false, cannot be restored to true, and advertises
# the disabled state to the service.
require(r"public static var areStoriesEnabled: Bool \{\s*#if KIVO_APP_STORE_LITE\s*false", story_manager)
require(r"#if KIVO_APP_STORE_LITE\s*let effectiveValue = false", story_manager)
require(r"#if KIVO_APP_STORE_LITE\s*\[\"X-Signal-Receive-Stories\": \"false\"\]", story_manager)
require(r"processIncomingStoryMessage[\s\S]*?#if KIVO_APP_STORE_LITE\s*throw OWSGenericError", story_manager)
require(r"processStoryMessageTranscript[\s\S]*?#if KIVO_APP_STORE_LITE\s*throw OWSGenericError", story_manager)

# Lite startup, receive, tab, settings and direct-navigation paths cannot reach
# Story creation or presentation. Compatibility enums/models remain compiled.
forbid_lite("TSPrivateStoryThread.getOrCreateMyStory", story_manager)
forbid_lite("StoryMessage.create(withIncomingStoryMessage:", story_manager)
forbid_lite("StoryMessage.create(withSentTranscript:", story_manager)
forbid_lite("tabs.append(.stories)", home_tabs)
forbid_lite("StoryPrivacySettingsViewController()", settings)
forbid_lite("homeVC.storiesViewController", split_view)
forbid_lite("self?.presentStoryViewController()", avatar_view)
forbid_lite("self?.observeRegistrationChanges()", system_story_manager)
forbid_lite("self?.enqueueOnboardingStoryDownload()", system_story_manager)
forbid_lite("urlSessionForUpdates2()", system_story_manager)
forbid_lite("showMyStories(appReadiness:", notification_actions)
forbid_lite("showGroupStoryReplyThread(notificationMessage:", notification_actions)
forbid_lite("StoryPageViewController(", notification_actions)
forbid_lite("StoryPageViewController(", conversation_delegate)
forbid_lite("StoryFinder.story(timestamp:", conversation_delegate)
forbid_lite("TextStoryComposerView", photo_capture)
forbid_lite("LinkPreviewAttachmentViewController", photo_capture)
forbid_lite("ComposerTypeSelectionControl", photo_capture)
forbid_lite("LinkPreviewAttachmentViewController", link_preview_attachment)
forbid_lite("ComposerTypeSelectionControl", media_controls)
require(
    r"enqueueOnboardingStoryDownload[\s\S]*?#if KIVO_APP_STORE_LITE[\s\S]*?return Task \{\}",
    system_story_manager,
)
require(
    r"notifyUserOfBackupsMediaError[\s\S]*?#if KIVO_APP_STORE_LITE[\s\S]*?defaultAction = \.showBackupsSettings[\s\S]*?#else[\s\S]*?defaultAction = \.submitDebugLogsForBackupsMediaError",
    notification_presenter,
)
require(
    r"downloadOnboardingStoryIfUndownloaded[\s\S]*?#if KIVO_APP_STORE_LITE[\s\S]*?Stories are disabled in Kivo App Store Lite",
    system_story_manager,
)

require(
    r"enqueueApprovedMedia[\s\S]*?#if KIVO_APP_STORE_LITE[\s\S]*?Stories are disabled in Kivo App Store Lite",
    "SignalUI/AttachmentMultisend/AttachmentMultisend.swift",
)
require(
    r"enqueueTextStory[\s\S]*?#if KIVO_APP_STORE_LITE\s*throw OWSAssertionError",
    "SignalUI/Stories/StorySharing.swift",
)
require(
    r"#if KIVO_APP_STORE_LITE\s*self\.storiesOnly = false\s*self\.showsStoriesInPicker = false",
    "Signal/src/ViewControllers/CameraFirstCaptureSendFlow.swift",
)
require(
    r"didChangeViewOnceState[\s\S]*?#if KIVO_APP_STORE_LITE\s*self\.showsStoriesInPicker = false",
    "Signal/src/ViewControllers/CameraFirstCaptureSendFlow.swift",
)
forbid_lite(
    "self.pickerVC.sectionOptions.insert(.stories)",
    "Signal/src/ViewControllers/ForwardMessageViewController.swift",
)

print("PASS  App Store Lite Stories core, receive, send, tab, settings, navigation, avatar, forward, camera and text-composer gates")
PY
