import sys
from . import OnepifEntryProperty as oep

TYPES = {
    "112": "API Credential",
    "wallet.financial.BankAccountUS": "Bank Account",
    "wallet.financial.CreditCard": "Credit Card",
    "wallet.computer.Database": "Database",
    # Not exported: Document
    "wallet.government.DriversLicense": "Driver License",
    "wallet.onlineservices.Email.v2": "Email Account",
    "identities.Identity": "Identity",
    "webforms.WebForm": "Login",
    "113": "Medical Record",
    "wallet.membership.Membership": "Membership",
    "wallet.government.HuntingLicense": "Outdoor License",
    "wallet.government.Passport": "Passport",
    "passwords.Password": "Password",
    "wallet.membership.RewardProgram": "Reward Program",
    "securenotes.SecureNote": "Secure Note",
    "wallet.computer.UnixServer": "Server",
    "wallet.government.SsnUS": "Social Security Number",
    "wallet.computer.License": "Software License",
    "wallet.computer.Router": "Wireless Router",
}

ANSI_RED = u"\u001b[1;31m"
ANSI_RESET = u"\u001b[0m"

class OnepifEntry():

    def __init__(self, data):
        self.raw = data
        self.set_type(data["typeName"])
        self.properties = []
        self.parse()

    def set_type(self, new_type: str):
        if new_type not in TYPES:
            raise Exception("Unknown record type: {}".format(new_type))
        self.type = new_type
        self.type_name = TYPES[new_type]

    def get_tags(self) -> list:
        if "openContents" not in self.raw:
            return []
        if "tags" not in self.raw["openContents"]:
            return []
        return self.raw["openContents"]["tags"]

    def get_totps(self) -> list:
        totp_fields = []
        if "sections" in self.raw["secureContents"]:
            for section in self.raw["secureContents"]["sections"]:
                if "fields" not in section:
                    continue
                for field in section["fields"]:
                    if field["n"][:5] == "TOTP_":
                        totp_fields.append([
                            field["v"],
                            field["t"],   # Custom title, if set (isn't displayed in 1P)
                        ])
        if len(totp_fields) == 0:
            return None
        return totp_fields

    def is_trash(self) -> bool:
        if "trashed" in self.raw:
            return self.raw["trashed"]
        return False

    def add_property(self, property: oep.OnepifEntryProperty):
        self.properties.append(property)

    def get_property_keys(self):
        keys = []
        for p in self.properties:
            keys.append(p.name)
        keys = list(set(keys))
        return keys

    def get_property(self, key: str):
        props = []
        for p in self.properties:
            if p.name == key:
                props.append(p)
        if not props:
            return None
        elif len(props) > 1:
            print("{}Warning: Multiple properties matching '{}' found: {}. Ignoring all but the first.{}".format(ANSI_RED, key, repr(props), ANSI_RESET))
        return props[0]

    def add_with_unique_key(self, prop_dict: dict, new_key: str, new_value):
        suffix_ctr = 0
        tmp_key = new_key
        while tmp_key in prop_dict:
            suffix_ctr += 1
            tmp_key = "{}_{}".format(new_key, suffix_ctr)
        if type(new_value) is str:
            # For some reason 1P sometimes exports 0x10 character for empty strings
            new_value = new_value.replace("\x10", "")
        prop_dict[tmp_key] = new_value

    def parse_section(self, section: dict):
        sect_title = section["title"]
        for f in section["fields"]:
            if "v" not in f:
                # Skip fields without data
                continue
            prop = oep.OnepifEntryProperty.from_sectionfield(f, sect_title)
            self.add_property(prop)

    def parse_fields(self, fields: list):
        for f in fields:
            prop = oep.OnepifEntryProperty.from_webfield(f)
            if prop:
                self.add_property(prop)

    def add_simple_prop(self, key: str, value):
        if value == "\x10":
            # this seems to be an "empty" indicator, so skip this
            return False
        prop = oep.OnepifEntryProperty(key, value)
        self.add_property(prop)

    def parse(self):
        for k, v in self.raw.items():
            if k in ["openContents", "secureContents"]:
                # handle open/secure groups of properties
                for k2, v2 in v.items():
                    if k2 == "unknown_details":
                        # special handling aka. black magic
                        if "sections" in v2:
                            k2 = "sections"
                            v2 = v2["sections"]
                    if k2 == "sections":
                        # handle section
                        for s in v2:
                            if "fields" not in s:
                                # Skip empty sections
                                continue
                            self.parse_section(s)
                        continue
                    elif k2 == "fields":
                        # For some reason this differs from the "fields" in a section
                        self.parse_fields(v2)
                        continue
                    # Handle all other values (most probably string or int)
                    self.add_simple_prop(k2, v2)
                continue
            # Handle all other values
            self.add_simple_prop(k, v)
        # TODO: Maybe walk all keys and see if there's (xxx_dd), xxx_mm, xxx_yy and turn them into a date