import copy

from rpft.rapidpro.utils import generate_new_uuid
from rpft.rapidpro.models.common import FlowReference, Group, SystemContactField


class CampaignEvent:
    def __init__(
        self,
        offset,
        unit,
        event_type,
        delivery_hour,
        start_mode,
        uuid=None,
        relative_to=None,
        relative_to_key=None,
        relative_to_label=None,
        message=None,
        flow=None,
        flow_name=None,
        flow_uuid=None,
        base_language=None,
    ):
        self.uuid = uuid if uuid else generate_new_uuid()
        self.offset = offset
        self.unit = unit
        self.event_type = event_type
        self.delivery_hour = delivery_hour
        # dict, keys: language IDs, values: message text
        self.message = message
        self.relative_to = relative_to or SystemContactField(
            relative_to_label,
            relative_to_key,
        )
        self.start_mode = start_mode
        self.flow = flow or FlowReference(flow_name, flow_uuid)
        self.base_language = base_language

        if event_type == "M" and (message is None or base_language is None):
            raise ValueError(
                "CampaignEvent must have a message and base_language if the event_type"
                " is M"
            )

        if event_type == "F" and self.flow is None:
            raise ValueError("CampaignEvent must have a flow if the event_type is F")

    def from_dict(data):
        data_copy = copy.deepcopy(data)
        data_copy["relative_to"] = SystemContactField(
            data_copy["relative_to"]["label"],
            data_copy["relative_to"]["key"],
        )

        if "flow" in data_copy:
            data_copy["flow"] = FlowReference(**data_copy["flow"])

        return CampaignEvent(**data_copy)

    def record_global_uuids(self, uuid_dict):
        if self.flow is not None:
            self.flow.record_uuid(uuid_dict)

    def assign_global_uuids(self, uuid_dict):
        if self.flow is not None:
            self.flow.assign_uuid(uuid_dict)

    def render(self):
        data = {
            "uuid": self.uuid,
            "offset": self.offset,
            "unit": self.unit,
            "event_type": self.event_type,
            "delivery_hour": self.delivery_hour,
            "message": self.message,
            "relative_to": self.relative_to.render(),
            "start_mode": self.start_mode,
        }

        if self.event_type == "F" and self.flow:
            data["flow"] = self.flow.render()

        if self.event_type == "M" and self.base_language:
            data["base_language"] = self.base_language

        return data


class Campaign:
    def __init__(
        self, name, group=None, group_name=None, group_uuid=None, events=None, uuid=None
    ):
        self.name = name
        self.group = group or Group(group_name, group_uuid)
        self.uuid = uuid if uuid else generate_new_uuid()
        self.events = events or []

    def add_event(self, event):
        self.events.append(event)

    def from_dict(data):
        assert "group" in data
        assert "name" in data
        assert "events" in data
        return Campaign(
            uuid=data.get("uuid"),
            name=data["name"],
            group=Group.from_dict(data["group"]),
            events=[CampaignEvent.from_dict(event) for event in data["events"]],
        )

    def record_global_uuids(self, uuid_dict):
        for event in self.events:
            event.record_global_uuids(uuid_dict)
        self.group.record_uuid(uuid_dict)

    def assign_global_uuids(self, uuid_dict):
        for event in self.events:
            event.assign_global_uuids(uuid_dict)
        self.group.assign_uuid(uuid_dict)

    def render(self):
        return {
            "group": self.group.render(),
            "name": self.name,
            "uuid": self.uuid,
            "events": [event.render() for event in self.events],
        }
