import logging
import re
from datetime import datetime, timezone

from soco import SoCo  # type: ignore

from soco_cli.api import run_command


def track_follow(
    speaker: SoCo,
    use_local_speaker_list: bool = False,
    break_on_pause: bool = True,
    compact: bool = False,
):
    """Print out the 'track' details each time the track changes.

    Args:
        speaker (SoCo): The speaker to follow.
        use_local_speaker_list (bool, optional): Use cached discovery.
        break_on_pause (bool, optional): Whether to return control if the
            speaker enters the paused or stopped playback states.
        compact (bool, optional): Whether to use 'compact' output mode.

    This function operates as if 'outside' the main program logic, because
    it needs to output intermediate results as it executes. Hence, the
    'run_command()' API call is used.
    """

    def timestamp(short=False):
        local_tz = datetime.now(timezone.utc).astimezone().tzinfo
        if not short:
            return datetime.now(tz=local_tz).strftime("%H:%M:%S (%Z) %d-%b-%Y")
        else:
            return datetime.now(tz=local_tz).strftime("%H:%M")

    counter = 1
    print()
    while True:
        # If stopped, wait for the speaker to start playback
        _, state, _ = run_command(
            speaker, "state", use_local_speaker_list=use_local_speaker_list
        )
        if state in [
            "STOPPED",
            "PAUSED_PLAYBACK",
        ]:
            if not compact:
                print(
                    " [{}] Playback is stopped or paused at {}\n".format(
                        speaker.player_name, timestamp()
                    ),
                )
            else:
                print(
                    "{:5d}: [{}] Playback is stopped or paused".format(
                        counter, timestamp(short=True)
                    )
                )
                counter += 1
            if break_on_pause:
                logging.info("Playback is paused/stopped; returning")
                break
            logging.info("Playback is paused/stopped; waiting for start")
            run_command(
                speaker, "wait_start", use_local_speaker_list=use_local_speaker_list
            )
            logging.info("Speaker has started playback")

        # Print the track info
        exit_code, output, error_msg = run_command(
            speaker, "track", use_local_speaker_list=use_local_speaker_list
        )
        if exit_code == 0:
            # Manipulate output
            if "Using Line In" in output:
                line_in = True
                output = "   Playing from Line In\n"
            else:
                line_in = False
                output = output.split("\n ", 1)[1]
            if not compact:
                # Remove some of the line entries
                output = re.sub(".*Playback.*\\n", "", output)
                # output = re.sub(".*Elapsed.*\\n", "", output)
                output = re.sub(".*URI.*\\n", "", output)
                output = re.sub(".*Uri.*\\n", "", output)
                # Prefix speaker name and timestamp
                output = (
                    " [{}] Playing at ".format(speaker.player_name)
                    + timestamp()
                    + ":\n"
                    + output
                )
            else:  # Compact (one line) output
                if line_in:
                    output = "{:5d}: [{}] Playing from Line In".format(
                        counter, timestamp(short=True)
                    )
                else:
                    # Ordering of keys determines output order
                    keys = [
                        "Channel:",
                        "Radio Show:",
                        "Artist:",
                        "Creator(s):",
                        "Book Title:",
                        "Chapter:",
                        "Album:",
                        "Podcast:",
                        "Title:",
                        "Episode:",
                        "Release Date:",
                        "Narrator(s):",
                    ]
                    elements = {}
                    for line in output.splitlines():
                        for key in keys:
                            if key in line:
                                elements[key] = line.replace(key, "").lstrip()
                    output = "{:5d}: [{}] ".format(counter, timestamp(short=True))

                    # Prune fields for audio books
                    if "Book Title:" in elements:
                        elements.pop("Title:", None)
                        elements.pop("Narrator(s):", None)
                    first = True
                    for key in keys:
                        value = elements.pop(key, None)
                        if value:
                            if not first:
                                output = output + "| "
                            else:
                                first = False
                            output = output + key + " " + value + " "
            print(output)
        else:
            error_out = "{:5d}: [{}] {}".format(
                counter, timestamp(short=True), error_msg
            )
            print(error_out)

        logging.info("Waiting for end of track")
        run_command(
            speaker, "wait_end_track", use_local_speaker_list=use_local_speaker_list
        )
        counter += 1
