import base64
import logging
import json
import boto3
from datetime import datetime, timezone


# Android Client event names
ANDROID_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME = "openOmniplayerPauseHook"
ANDROID_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME = "autoRepeatPlayHook"

# iOS Client event names
IOS_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME = "TapSongPillPauseHook"
IOS_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME = "AutoRepeatPlaySameHook"

# Events that are the same on Android and iOS
CLIENT_EVENT_REMIX_TAPPED_NAME = "remix_tapped"

# Names of the event we log to rec-events-stream
REC_EVENT_STREAM_HOOKS_OPEN_OMNIPLAYER_NAME = "HooksOpenOmniPlayer"
REC_EVENT_STREAM_HOOKS_TAP_REMIX_NAME = "HooksTapRemix"
REC_EVENT_STREAM_HOOKS_REPEAT_WATCH_NAME = "HooksRepeatWatch"

# List of events we know unambiguously are hook events
UNAMBIGUOUS_HOOK_EVENTS = [
    # Open Omniplayer related events
    IOS_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME,  # iOS
    ANDROID_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME,  # Android
    # Repeat watch events
    IOS_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME,  # iOS
    ANDROID_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME,  # Android
]

CLIENT_EVENT_NAME_TO_REC_EVENT_NAME = {
    # Open Omniplayer events
    IOS_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME: REC_EVENT_STREAM_HOOKS_OPEN_OMNIPLAYER_NAME,
    ANDROID_CLIENT_EVENT_OPEN_OMNIPLAYER_NAME: REC_EVENT_STREAM_HOOKS_OPEN_OMNIPLAYER_NAME,
    # Tap remix event
    CLIENT_EVENT_REMIX_TAPPED_NAME: REC_EVENT_STREAM_HOOKS_TAP_REMIX_NAME,
    # Repeat watch events
    IOS_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME: REC_EVENT_STREAM_HOOKS_REPEAT_WATCH_NAME,
    ANDROID_CLIENT_EVENT_HOOK_REPEAT_WATCH_NAME: REC_EVENT_STREAM_HOOKS_REPEAT_WATCH_NAME,
}

RECS_EVENTS_KINESIS_CLIENT = boto3.client(
    "kinesis",
    region_name="us-east-2",
)

logger = logging.getLogger(__name__)


def _is_hook_event(properties):
    action_name = properties.get("actionName", "")
    # We want to guard against the case where the client has not
    # set the elementType properly. If we know the event name corresponds
    # to a hook event, just return True.
    if action_name in UNAMBIGUOUS_HOOK_EVENTS:
        return True

    # Otherwise, see if the client has set the elementType properly.
    elementType = properties.get("elementType", "")
    return elementType == "hook"


def lambda_handler(event, context):
    """
    Lambda handler to check if an event name is in hook_events list and log to RECS_EVENTS_KINESIS stream
    """
    try:
        if "Records" not in event:
            return
        for record in event["Records"]:
            process_record(record)

        return {"statusCode": 200, "body": json.dumps("Success")}
    except Exception as e:
        print(f"Error in lambda_handler: {str(e)}")
        return {"statusCode": 500, "body": json.dumps(f"Error: {str(e)}")}


def process_record(record):
    """
    Process a single record and check if it should be logged to RECS_EVENTS_KINESIS
    Unlike the web hook events, all mobile events have the event name 'App-Event', so we can't filter out there.
    We can just filter out events if they have a hook ID.
    """

    if "kinesis" not in record:
        return
    kinesis = record["kinesis"]
    if "data" not in kinesis:
        return

    payload = base64.b64decode(record["kinesis"]["data"])
    payload_as_json = json.loads(payload)

    request_body = payload_as_json.get("request_body", "")
    if not request_body:
        return

    decoded_request_body = json.loads(base64.b64decode(request_body))

    properties = decoded_request_body.get("properties", {})
    if not properties:
        return

    if not _is_hook_event(properties):
        return

    action_name = properties.get("actionName", "")
    rec_event_name = CLIENT_EVENT_NAME_TO_REC_EVENT_NAME.get(action_name, "")
    if not rec_event_name:
        return

    hook_id = properties.get("elementId", "")
    if not hook_id:
        return
    user_id = properties.get("userId", "")
    if not user_id:
        return

    recs_event = {}
    recs_event["name"] = rec_event_name
    recs_event["source"] = "mobile"
    recs_event["user_id"] = user_id
    recs_event["timestamp"] = str(datetime.now(timezone.utc).isoformat())

    recs_event["properties"] = {
        "hook_id": hook_id,
    }

    logger.info(f"Logging {rec_event_name} event: {recs_event}")

    RECS_EVENTS_KINESIS_CLIENT.put_record(
        StreamName="rec-events-stream",
        Data=json.dumps(recs_event),
        PartitionKey=str(datetime.now(timezone.utc).isoformat()),
    )
