# Copyright 2021 The Pigweed Authors
#
# 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
#
#     https://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.
"""Library to assist processing Snapshot Metadata protos into text"""

from typing import Optional, List, Mapping
import pw_tokenizer
from pw_tokenizer import proto as proto_detokenizer
from pw_snapshot_metadata_proto import snapshot_metadata_pb2

_PRETTY_FORMAT_DEFAULT_WIDTH = 80


def _process_tags(tags: Mapping[str, str]) -> Optional[str]:
    """Outputs snapshot tags as a multi-line string."""
    if not tags:
        return None

    output: List[str] = ['Tags:']
    for key, value in tags.items():
        output.append(f'  {key}: {value}')

    return '\n'.join(output)


def process_snapshot(serialized_snapshot: bytes,
                     tokenizer_db: Optional[pw_tokenizer.Detokenizer]) -> str:
    """Processes snapshot metadata and tags, producing a multi-line string."""
    snapshot = snapshot_metadata_pb2.SnapshotBasicInfo()
    snapshot.ParseFromString(serialized_snapshot)

    output: List[str] = []

    if snapshot.HasField('metadata'):
        output.extend((
            str(MetadataProcessor(snapshot.metadata, tokenizer_db)),
            '',
        ))

    if snapshot.tags:
        tags = _process_tags(snapshot.tags)
        if tags:
            output.append(tags)
        # Trailing blank line for spacing.
        output.append('')

    return '\n'.join(output)


class MetadataProcessor:
    """This class simplifies dumping contents of a snapshot Metadata message."""
    def __init__(self, metadata: snapshot_metadata_pb2.Metadata,
                 tokenizer_db: Optional[pw_tokenizer.Detokenizer]):
        self._metadata = metadata
        self._tokenizer_db = (tokenizer_db if tokenizer_db is not None else
                              pw_tokenizer.Detokenizer(None))
        self._format_width = _PRETTY_FORMAT_DEFAULT_WIDTH
        proto_detokenizer.detokenize_fields(self._tokenizer_db, self._metadata)

    def is_fatal(self) -> bool:
        return self._metadata.fatal

    def reason(self) -> str:
        return self._metadata.reason.decode(
        ) if self._metadata.reason else 'UNKNOWN (field missing)'

    def project_name(self) -> str:
        return self._metadata.project_name.decode()

    def device_name(self) -> str:
        return self._metadata.device_name.decode()

    def device_fw_version(self) -> str:
        return self._metadata.software_version

    def snapshot_uuid(self) -> str:
        return self._metadata.snapshot_uuid.hex()

    def fw_build_uuid(self) -> str:
        return self._metadata.software_build_uuid.hex()

    def set_pretty_format_width(self, width: int):
        """Sets the centered width of the FATAL text for a formatted output."""
        self._format_width = width

    def __str__(self) -> str:
        """outputs a pw.snapshot.Metadata proto as a multi-line string."""
        output: List[str] = []
        if self._metadata.fatal:
            output.extend((
                '▪▄▄▄ ▄▄▄· ▄▄▄▄▄ ▄▄▄· ▄ ·'.center(self._format_width).rstrip(),
                '█▄▄▄▐█ ▀█ • █▌ ▐█ ▀█ █  '.center(self._format_width).rstrip(),
                '█ ▪ ▄█▀▀█   █. ▄█▀▀█ █  '.center(self._format_width).rstrip(),
                '▐▌ .▐█ ▪▐▌ ▪▐▌·▐█ ▪▐▌▐▌ '.center(self._format_width).rstrip(),
                '▀    ▀  ▀ ·  ▀  ▀  ▀ .▀▀'.center(self._format_width).rstrip(),
                '',
                'Device crash cause:',
            ))
        else:
            output.append('Snapshot capture reason:')

        output.extend((
            '    ' + self.reason(),
            '',
        ))

        if self._metadata.project_name:
            output.append(f'Project name:      {self.project_name()}')

        if self._metadata.device_name:
            output.append(f'Device:            {self.device_name()}')

        if self._metadata.software_version:
            output.append(f'Device FW version: {self.device_fw_version()}')

        if self._metadata.software_build_uuid:
            output.append(f'FW build UUID:     {self.fw_build_uuid()}')

        if self._metadata.snapshot_uuid:
            output.append(f'Snapshot UUID:     {self.snapshot_uuid()}')

        return '\n'.join(output)
