# -----------------------------------------------------------------------------
# This piece of work is inspired by Pollere' VerSec:
# https://github.com/pollere/DCT
# But this code is implemented independently without using any line of the
# original one, and released under Apache License.
#
# Copyright (C) 2019-2022 The python-ndn authors
#
# This file is part of python-ndn.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
import logging
from ...encoding import BinaryStr, SignaturePtrs, FormalName, parse_data, Name
from ...app import NDNApp, Validator
from ...security import union_checker
from ...security.validator.cascade_validator import CascadeChecker, PublicKeyStorage, MemoryKeyStorage
from .checker import Checker

__all__ = ['lvs_validator']


def lvs_validator(checker: Checker, app: NDNApp, trust_anchor: BinaryStr,
                  storage: PublicKeyStorage = MemoryKeyStorage()) -> Validator:
    async def validate_name(name: FormalName, sig_ptrs: SignaturePtrs) -> bool:
        if (not sig_ptrs.signature_info or not sig_ptrs.signature_info.key_locator
                or not sig_ptrs.signature_info.key_locator.name):
            return False
        cert_name = sig_ptrs.signature_info.key_locator.name
        logging.debug(f'LVS Checking {Name.to_str(name)} <- {Name.to_str(cert_name)} ...')
        return checker.check(name, cert_name)

    def sanity_check():
        root_of_trust = checker.root_of_trust()
        if not checker.validate_user_fns():
            raise ValueError('Missing user functions for LVS validator')
        cert_name, _, _, _ = parse_data(trust_anchor)
        ta_matches = sum((m[0] for m in checker.match(cert_name)), start=[])
        if not ta_matches or not root_of_trust.issubset(ta_matches):
            raise ValueError('Trust anchor does not match all roots of trust of LVS model')

    sanity_check()
    cas_checker = CascadeChecker(app, trust_anchor, storage)
    ret = union_checker(validate_name, cas_checker)
    cas_checker.next_level = ret
    return ret
