#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.

import re
import threading
import time

from fenrirscreenreader.core.i18n import _


class command:
    def __init__(self):
        pass

    def initialize(self, environment):
        self.env = environment
        # Use commandBuffer like other commands
        if "progressMonitoring" not in self.env["commandBuffer"]:
            # Check if progress monitoring should be enabled by default from
            # settings
            try:
                default_enabled = self.env["runtime"][
                    "SettingsManager"
                ].get_setting_as_bool("sound", "progressMonitoring")
            except Exception as e:
                # If setting doesn't exist, default to False
                default_enabled = False
            self.env["commandBuffer"]["progressMonitoring"] = default_enabled
            self.env["commandBuffer"]["lastProgressTime"] = 0
            self.env["commandBuffer"]["lastProgressValue"] = -1

    def shutdown(self):
        self.stop_progress_monitoring()

    def get_description(self):
        return _("Toggle progress bar monitoring with ascending tones")

    def run(self):
        # Check if commandBuffer exists
        if "progressMonitoring" not in self.env["commandBuffer"]:
            self.env["commandBuffer"]["progressMonitoring"] = False
            self.env["commandBuffer"]["lastProgressTime"] = 0
            self.env["commandBuffer"]["lastProgressValue"] = -1

        if self.env["commandBuffer"]["progressMonitoring"]:
            self.stop_progress_monitoring()
            self.env["runtime"]["OutputManager"].present_text(
                _("Progress monitoring disabled"), interrupt=True
            )
        else:
            self.start_progress_monitoring()
            self.env["runtime"]["OutputManager"].present_text(
                _("Progress monitoring enabled"), interrupt=True
            )

    def start_progress_monitoring(self):
        self.env["commandBuffer"]["progressMonitoring"] = True
        self.env["commandBuffer"]["lastProgressTime"] = time.time()
        self.env["commandBuffer"]["lastProgressValue"] = -1
        # Don't control speech - let user decide with silence_until_prompt

    def stop_progress_monitoring(self):
        self.env["commandBuffer"]["progressMonitoring"] = False
        # Don't control speech - progress monitor is beep-only

    def detect_progress(self, text):
        if not self.env["commandBuffer"]["progressMonitoring"]:
            return

        # Skip progress detection if current screen looks like a prompt
        if self.is_current_line_prompt():
            return

        current_time = time.time()

        # Pattern 1: Percentage (50%, 25.5%, etc.)
        percent_match = re.search(r"(\d+(?:\.\d+)?)\s*%", text)
        if percent_match:
            percentage = float(percent_match.group(1))
            if percentage != self.env["commandBuffer"]["lastProgressValue"]:
                self.play_progress_tone(percentage)
                self.env["commandBuffer"]["lastProgressValue"] = percentage
                self.env["commandBuffer"]["lastProgressTime"] = current_time
            return

        # Pattern 2: Fraction (15/100, 3 of 10, etc.)
        fraction_match = re.search(r"(\d+)\s*(?:of|/)\s*(\d+)", text)
        if fraction_match:
            current = int(fraction_match.group(1))
            total = int(fraction_match.group(2))
            if total > 0:
                percentage = (current / total) * 100
                if (
                    percentage
                    != self.env["commandBuffer"]["lastProgressValue"]
                ):
                    self.play_progress_tone(percentage)
                    self.env["commandBuffer"]["lastProgressValue"] = percentage
                    self.env["commandBuffer"][
                        "lastProgressTime"
                    ] = current_time
                return

        # Pattern 3: Progress bars ([####    ], [====>   ], etc.)
        # Improved pattern to avoid matching IRC channels like [#channel]
        bar_match = re.search(r"\[([#=\-\*]+)([\s\.]*)\]", text)
        if bar_match:
            filled = len(bar_match.group(1))
            unfilled = len(bar_match.group(2))
            total = filled + unfilled
            # Require at least 2 progress chars total and unfilled portion must
            # be spaces/dots
            if total >= 2 and (
                not bar_match.group(2)
                or re.match(r"^[\s\.]*$", bar_match.group(2))
            ):
                percentage = (filled / total) * 100
                if (
                    percentage
                    != self.env["commandBuffer"]["lastProgressValue"]
                ):
                    self.play_progress_tone(percentage)
                    self.env["commandBuffer"]["lastProgressValue"] = percentage
                    self.env["commandBuffer"][
                        "lastProgressTime"
                    ] = current_time
                return

        # Pattern 4: Generic activity indicators (Loading..., Working..., etc.)
        activity_pattern = re.search(
            (
                r"(loading|processing|working|installing|downloading|"
                r"compiling|building).*\.{2,}"
            ),
            text,
            re.IGNORECASE,
        )
        if activity_pattern:
            # Play a steady beep every 2 seconds for ongoing activity
            if (
                current_time - self.env["commandBuffer"]["lastProgressTime"]
                >= 2.0
            ):
                self.play_activity_beep()
                self.env["commandBuffer"]["lastProgressTime"] = current_time

    def play_progress_tone(self, percentage):
        # Map 0-100% to 400-1200Hz frequency range
        frequency = 400 + (percentage * 8)
        frequency = max(400, min(1200, frequency))  # Clamp to safe range
        self.env["runtime"]["OutputManager"].play_frequence(
            frequency, 0.15, interrupt=False
        )

    def play_activity_beep(self):
        # Single tone for generic activity
        self.env["runtime"]["OutputManager"].play_frequence(
            800, 0.1, interrupt=False
        )

    def is_current_line_prompt(self):
        """Check if the current line looks like a standalone prompt (not command with progress)"""
        import re

        try:
            # Get the current screen content
            if not self.env["screen"]["new_content_text"]:
                return False

            lines = self.env["screen"]["new_content_text"].split("\n")
            if not lines:
                return False

            # Check the last line (most common) and current cursor line for
            # prompt patterns
            lines_to_check = []

            # Add last line (most common for prompts)
            if lines:
                lines_to_check.append(lines[-1])

            # Add current cursor line if different from last line
            if (
                self.env["screen"]["new_cursor"]["y"] < len(lines)
                and self.env["screen"]["new_cursor"]["y"] != len(lines) - 1
            ):
                lines_to_check.append(
                    lines[self.env["screen"]["new_cursor"]["y"]]
                )

            # Standalone prompt patterns (no commands mixed in)
            standalone_prompt_patterns = [
                r"^\s*\$\s*$",  # Just $ (with whitespace)
                r"^\s*#\s*$",  # Just # (with whitespace)
                r"^\s*>\s*$",  # Just > (with whitespace)
                r"^\[.*\]\s*[\\\$#>]\s*$",  # [path]$ without commands
                r"^[a-zA-Z0-9._-]+[\\\$#>]\s*$",  # bash-5.1$ without commands
                # Interactive prompt patterns (these ARE standalone)
                r".*\?\s*\[[YyNn]/[YyNn]\]\s*$",  # ? [Y/n] or ? [y/N] style
                r".*\?\s*\[[Yy]es/[Nn]o\]\s*$",  # ? [Yes/No] style
                # "continue? [Y/n]" style
                r".*continue\?\s*\[[YyNn]/[YyNn]\].*$",
                r"^::.*\?\s*\[[YyNn]/[YyNn]\].*$",  # pacman style prompts
                # Authentication prompts (these ARE standalone)
                r"^\[[Ss]udo\]\s*[Pp]assword\s*for\s+.*:\s*$",  # [sudo] password
                r"^[Pp]assword\s*:\s*$",  # Password:
                r".*[Pp]assword\s*:\s*$",  # general password prompts
                # Continuation prompts (these ARE standalone)
                r"^[Pp]ress\s+any\s+key\s+to\s+continue.*$",  # Press any key
                r"^[Aa]re\s+you\s+sure\?\s*.*$",  # Are you sure?
            ]

            for line in lines_to_check:
                line = line.strip()
                if not line:
                    continue

                # Check if this line contains both a prompt AND other content (like commands)
                # If so, don't treat it as a standalone prompt
                has_prompt_marker = bool(
                    re.search(r".*@.*[\\\$#>]", line)
                    or re.search(r"^\[.*\]\s*[\\\$#>]", line)
                )
                if has_prompt_marker:
                    # If line has prompt marker but also has significant content after it,
                    # it's a command line, not a standalone prompt
                    prompt_end = max(
                        line.rfind("$"),
                        line.rfind("#"),
                        line.rfind(">"),
                        line.rfind("\\"),
                    )
                    if (
                        prompt_end >= 0 and prompt_end < len(line) - 5
                    ):  # More than just whitespace after prompt
                        continue  # This is a command line, not a standalone prompt

                for pattern in standalone_prompt_patterns:
                    try:
                        if re.search(pattern, line):
                            return True
                    except re.error:
                        continue

            return False

        except Exception as e:
            # If anything fails, assume it's not a prompt to be safe
            return False

    def set_callback(self, callback):
        pass
