import boto3
import pendulum

from bloop import UUID, BaseModel, Column, Engine
from bloop.ext.pendulum import DateTime


def engine_for_region(region, table_name_template="{table_name}"):
    dynamodb = boto3.client("dynamodb", region_name=region)
    dynamodbstreams = boto3.client("dynamodbstreams", region_name=region)
    return Engine(
        dynamodb=dynamodb,
        dynamodbstreams=dynamodbstreams,
        table_name_template=table_name_template
    )


primary = engine_for_region("us-west-2", table_name_template="primary.{table_name}")
replica = engine_for_region("us-east-1", table_name_template="replica.{table_name}")


class SomeDataBlob(BaseModel):
    class Meta:
        stream = {
            "include": {"new", "old"}
        }

    id = Column(UUID, hash_key=True)
    uploaded = Column(DateTime, range_key=True)


primary.bind(SomeDataBlob)
replica.bind(SomeDataBlob)


def scan_replicate():
    """Bulk replicate existing data"""
    for obj in primary.scan(SomeDataBlob):
        replica.save(obj)


def stream_replicate():
    """Monitor changes in approximately real-time and replicate them"""
    stream = primary.stream(SomeDataBlob, "trim_horizon")
    next_heartbeat = pendulum.now()
    while True:
        now = pendulum.now()
        if now >= next_heartbeat:
            stream.heartbeat()
            next_heartbeat = now.add(minutes=10)

        record = next(stream)
        if record is None:
            continue
        if record["new"] is not None:
            replica.save(record["new"])
        else:
            replica.delete(record["old"])