#!/usr/bin/env python3
import os
import sys
import time
import subprocess
import logging
import shutil
import signal
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
# (No AsyncObserver)

# Set dynamic library path for whisper-cli if needed
os.environ["DYLD_LIBRARY_PATH"] = (
    "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/build/src:"
    "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/build/ggml/src:"
    "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/build/ggml/src/ggml-blas:"
    "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/build/ggml/src/ggml-metal"
)

# --- Configuration ---
HOME = os.path.expanduser("~")
BASE_DIR = os.path.join(HOME, "Dropbox", "_INBOX_RECEIVING", "__AUDIO-IN")
INPUT_DIR = os.path.join(BASE_DIR, "_01_Input")
PROCESSED_DIR = os.path.join(BASE_DIR, "_02_Processed")
TRANSCRIPT_DIR = os.path.join(BASE_DIR, "_03_Transcripts")
LOGS_DIR = os.path.join(BASE_DIR, "_LOGS")

# Paths for external tools
FFMPEG_CMD = "ffmpeg"
WHISPER_CPP_CMD = "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/build/bin/whisper-cli"
WHISPER_MODEL = "/Users/bertm/Dropbox/_INBOX_RECEIVING/__AUDIO-IN/whisper.cpp-master/models/ggml-base.en.bin"

# --- Logging Setup ---
os.makedirs(LOGS_DIR, exist_ok=True)
logging.basicConfig(
    filename=os.path.join(LOGS_DIR, "unified_process.log"),
    level=logging.DEBUG,
    format="%(asctime)s [%(levelname)s] %(message)s",
)
console = logging.StreamHandler(sys.stdout)
console.setLevel(logging.INFO)
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s")
console.setFormatter(formatter)
logging.getLogger("").addHandler(console)

# --- Utility Functions ---
def run_ffmpeg_conversion(input_file, output_file):
    logging.info(f"Converting {input_file} to {output_file}")
    cmd = [
        FFMPEG_CMD,
        "-i", input_file,
        "-vn",
        "-acodec", "libmp3lame",
        "-q:a", "2",
        output_file,
    ]
    result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    if result.returncode == 0:
        logging.info(f"Successfully converted {input_file}")
        return True
    else:
        logging.error(f"FFmpeg conversion failed: {result.stderr.decode()}")
        return False

def transcribe_with_whisper(audio_file, transcript_file):
    logging.info(f"Starting transcription for {audio_file}")
    cmd = [
        WHISPER_CPP_CMD,
        "-m", WHISPER_MODEL,
        "-f", audio_file,
        "-l", "en"
    ]
    try:
        with open(transcript_file, "w") as out:
            result = subprocess.run(cmd, stdout=out, stderr=subprocess.PIPE)
        if result.returncode == 0:
            logging.info(f"Transcription completed for {audio_file}")
            return True
        else:
            logging.error(f"Transcription failed: {result.stderr.decode()}")
            return False
    except Exception as e:
        logging.exception(f"Exception during transcription: {e}")
        return False

# --- Event Handler ---
class AudioFileHandler(FileSystemEventHandler):
    def on_created(self, event):
        if event.is_directory:
            return
        filepath = event.src_path
        logging.info(f"New file detected: {filepath}")
        time.sleep(1)  # Allow file writing to finish

        filename = os.path.basename(filepath)
        name_no_ext, ext = os.path.splitext(filename)
        ext = ext.lower()

        processed_filename = f"{name_no_ext}_processed.mp3"
        processed_file = os.path.join(PROCESSED_DIR, processed_filename)
        transcript_file = os.path.join(TRANSCRIPT_DIR, f"{name_no_ext}_transcript.txt")

        for d in [INPUT_DIR, PROCESSED_DIR, TRANSCRIPT_DIR]:
            os.makedirs(d, exist_ok=True)

        # Conversion
        if ext != ".mp3":
            if run_ffmpeg_conversion(filepath, processed_file):
                os.remove(filepath)
                filepath = processed_file
            else:
                logging.error(f"Conversion failed for {filename}")
                return
        else:
            shutil.move(filepath, processed_file)
            filepath = processed_file

        logging.info(f"File ready for transcription: {filepath}")

        # Transcription
        if transcribe_with_whisper(filepath, transcript_file):
            logging.info(f"Transcription saved to {transcript_file}")
        else:
            logging.error(f"Transcription failed for {filename}")

# --- Main Service ---
def main():
    logging.info("Starting FAST async audio transcription service...")

    # Make sure the input directory exists
    os.makedirs(INPUT_DIR, exist_ok=True)

    event_handler = AudioFileHandler()
    observer = Observer()
    observer.schedule(event_handler, INPUT_DIR, recursive=False)
    observer.start()

    # Handle SIGINT and SIGTERM
    def shutdown(signum, frame):
        logging.info("Interrupt received. Shutting down...")
        observer.stop()

    signal.signal(signal.SIGINT, shutdown)
    signal.signal(signal.SIGTERM, shutdown)

    try:
        while observer.is_alive():
            time.sleep(0.5)
    except Exception as e:
        logging.exception(f"Unhandled exception: {e}")
    finally:
        observer.stop()
        observer.join()
        logging.info("Service stopped cleanly.")

if __name__ == "__main__":
    main()