# Copyright (C) 2020  Braiins Systems s.r.o.
#
# This file is part of Braiins Open-Source Initiative (BOSI).
#
# BOSI is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
#
# Please, keep in mind that we may also license BOSI or any part thereof
# under a proprietary license. For more information on the terms and conditions
# of such proprietary license or if you have any other questions, please
# contact us at opensource@braiins.com.

from enum import Enum
import logging

LOG = logging.getLogger(__name__)


class Target(Enum):
    am1 = 1
    am2 = 2
    wm1 = 3
    am3 = 4


class SubTarget(Enum):
    s9 = 1
    x17 = 2
    h3 = 3
    h6 = 4
    h6os = 5
    hxxx = 6
    bbb = 7


class S9Variant(str, Enum):
    S9 = 'S9'

    def __str__(self):
        return self.value


class X17Variant(str, Enum):
    X17 = 'X17'
    S17 = 'S17'
    T17 = 'T17'
    S17_Pro = 'S17 Pro'
    S17_Plus = 'S17+'
    T17_Plus = 'T17+'
    S17_e = 'S17e'
    T17_e = 'T17e'
    X19 = 'X19'
    S19 = 'S19'
    S19_Pro = 'S19 Pro'
    S19J_Pro = 'S19J Pro'
    S19J = 'S19J'
    S19_Plus = 'S19 Plus'
    T19 = 'T19'

    def __str__(self):
        return self.value


class Wm1Variant(str, Enum):
    Unknown = 'UNKNOWN'
    MxxS = 'MxxS'
    M20S_V10 = 'M20S_V10'
    M21S_V20 = 'M21S_V20'

    def __str__(self):
        return self.value


class TargetTriple:
    def __init__(self, target: Target, sub_target: SubTarget, variant):
        self.target = target
        self.sub_target = sub_target
        self.variant = variant

    @property
    def target_full_name(self):
        return '{}-{}'.format(self.target.name, self.sub_target.name)

    @staticmethod
    def _get_target_triple(model: str):
        exploded = model.split(maxsplit=1)
        if len(exploded) != 2:
            LOG.warning('Unknown miner model: %s' % model)
            return None
        vendor, variant = exploded
        if vendor not in ['Antminer', 'WhatsMiner']:
            LOG.warning('Unknown miner vendor: %s' % vendor)
            return None

        if variant in S9Variant.__members__.values():
            target = Target.am1
            sub_target = SubTarget.s9
            variant = S9Variant(variant)
        elif variant in X17Variant.__members__.values():
            # FIXME: the target cannot be determined from the model alone.
            #  e.g. for S19 model, there exist two mappings (am2-s17 and
            #  am3-bbb) and the mapping is ambiguous
            if variant == 'X19':
                target = Target.am3
                sub_target = SubTarget.bbb
                variant = X17Variant(variant)
            else:
                target = Target.am2
                sub_target = SubTarget.x17
                variant = X17Variant(variant)
        elif variant in Wm1Variant.__members__.values():
            target = Target.wm1
            sub_target = SubTarget.hxxx
            variant = Wm1Variant(variant)
        else:
            LOG.warning('Unknown miner variant: %s' % variant)
            return None

        return TargetTriple(target, sub_target, variant)


class MinerType(Enum):
    AntMiner = 0
    WhatsMiner = 1


class OsType(Enum):
    BOS = 1
    stock = 2
    Vnish = 3
    ASICseer = 4


class OsMode(Enum):
    nand = 1
    sd = 2
    recovery = 3
    upgrade = 4


class OsInfo:
    def __init__(self, os_type: OsType, mode: OsMode, version):
        self.type = os_type
        self.mode = mode
        self.version = version
