from __future__ import print_function
import json
from .util import parse_time, stable_hash, safe_text, timestamp


class Alert(object):
    def __init__(self, alert_id, properties, geometry=None, matched_areas=None):
        self.id = str(alert_id or properties.get("id") or stable_hash(properties))
        self.event = safe_text(properties.get("event"), 180)
        self.area_desc = safe_text(properties.get("areaDesc"), 600)
        self.headline = safe_text(properties.get("headline"), 900)
        self.description = safe_text(properties.get("description"), 12000)
        self.instruction = safe_text(properties.get("instruction"), 6000)
        self.severity = safe_text(properties.get("severity"), 50)
        self.urgency = safe_text(properties.get("urgency"), 50)
        self.certainty = safe_text(properties.get("certainty"), 50)
        self.status = safe_text(properties.get("status"), 50)
        self.message_type = safe_text(properties.get("messageType"), 50)
        self.sender_name = safe_text(properties.get("senderName"), 300)
        self.sent = properties.get("sent")
        self.effective = properties.get("effective")
        self.onset = properties.get("onset")
        self.expires = properties.get("expires")
        self.ends = properties.get("ends")
        self.geometry = geometry
        self.affected_zones = list(properties.get("affectedZones") or [])
        self.references = self._references(properties.get("references"))
        self.parameters = properties.get("parameters") or {}
        self.matched_areas = sorted(set(matched_areas or []))
        self.fingerprint = self.make_fingerprint()

    @staticmethod
    def _references(value):
        result = []
        for item in value or []:
            if isinstance(item, dict):
                candidate = item.get("@id") or item.get("id") or item.get("identifier")
            else:
                candidate = item
            if candidate:
                candidate = str(candidate)
                result.append(candidate)
                # CAP reference strings may use sender,identifier,sent triplets.
                parts = [part.strip() for part in candidate.split(",")]
                if len(parts) >= 2 and parts[1]:
                    result.append(parts[1])
        return sorted(set(result))

    @classmethod
    def from_feature(cls, feature, matched_areas=None):
        properties = feature.get("properties") or {}
        alert_id = feature.get("id") or properties.get("id")
        return cls(alert_id, properties, feature.get("geometry"), matched_areas)

    @classmethod
    def from_dict(cls, data):
        obj = cls(data.get("id"), data, data.get("geometry"), data.get("matched_areas"))
        obj.fingerprint = data.get("fingerprint") or obj.make_fingerprint()
        return obj

    def merge(self, other):
        self.matched_areas = sorted(set(self.matched_areas + other.matched_areas))
        self.affected_zones = sorted(set(self.affected_zones + other.affected_zones))
        self.references = sorted(set(self.references + other.references))
        self.fingerprint = self.make_fingerprint()
        return self

    def make_fingerprint(self):
        return stable_hash({
            "event": self.event,
            "area_desc": self.area_desc,
            "headline": self.headline,
            "description": self.description,
            "instruction": self.instruction,
            "severity": self.severity,
            "urgency": self.urgency,
            "certainty": self.certainty,
            "status": self.status,
            "message_type": self.message_type,
            "sent": self.sent,
            "effective": self.effective,
            "onset": self.onset,
            "expires": self.expires,
            "ends": self.ends,
            "matched_areas": self.matched_areas,
        })

    def start_time(self, basis):
        return parse_time(self.onset if str(basis).lower() == "onset" else self.effective)

    def end_time(self):
        return parse_time(self.ends or self.expires)

    def is_expired(self, now):
        end = self.end_time()
        return bool(end and timestamp(end) <= timestamp(now))

    def is_started(self, now, basis):
        start = self.start_time(basis)
        return not start or timestamp(start) <= timestamp(now)

    def to_dict(self):
        return {
            "id": self.id,
            "event": self.event,
            "areaDesc": self.area_desc,
            "headline": self.headline,
            "description": self.description,
            "instruction": self.instruction,
            "severity": self.severity,
            "urgency": self.urgency,
            "certainty": self.certainty,
            "status": self.status,
            "messageType": self.message_type,
            "senderName": self.sender_name,
            "sent": self.sent,
            "effective": self.effective,
            "onset": self.onset,
            "expires": self.expires,
            "ends": self.ends,
            "geometry": self.geometry,
            "affectedZones": self.affected_zones,
            "references": self.references,
            "parameters": self.parameters,
            "matched_areas": self.matched_areas,
            "fingerprint": self.fingerprint,
        }
