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

# =============================================================================
# AI TEMPO - Sistema de xestión de actividades diarias
# Para Raspberry Pi 5
# Descripción: Programa que avisa por voz e pantalla das actividades do día
# Sen parpadeo: usa escritura directa por posición de cursor (ANSI)
# só se reescribe a liña do reloxo cada segundo, o resto queda fixo
# =============================================================================

import time
import datetime
import subprocess
import sys
import os
import threading

# ─────────────────────────────────────────────────
# CONFIGURACIÓN DE CORES PARA O TERMINAL (ANSI)
# Usamos vermello brillante sobre fondo negro
# ─────────────────────────────────────────────────
COR_VERMELLO  = "\033[91m"    # Texto en vermello brillante
COR_AMARELO   = "\033[93m"    # Texto en amarelo (para cabeceira)
COR_CIAN      = "\033[96m"    # Texto en cian (para o reloxo)
FONDO_NEGRO   = "\033[40m"    # Fondo negro
NEGRITA       = "\033[1m"     # Negrita
RESTABLECER   = "\033[0m"     # Restablecer formato

# Secuencias de movemento de cursor ANSI
# Mover o cursor a fila F, columna 1 (filas comezan en 1)
def mover_cursor(fila):
    return f"\033[{fila};1H"

# Limpar dende o cursor ata fin de liña
LIMPAR_FIN_LIÑA = "\033[K"

# ─────────────────────────────────────────────────
# DÍAS DA SEMANA EN ESPAÑOL
# strftime con locale inglés pon "Wednesday" etc.
# Usamos un dicionario propio para evitalo
# ─────────────────────────────────────────────────
DIAS_ES = {
    0: "Lunes",
    1: "Martes",
    2: "Miércoles",
    3: "Jueves",
    4: "Viernes",
    5: "Sábado",
    6: "Domingo",
}

def formato_data(agora):
    """Devolve a data e hora con día da semana en español."""
    dia_semana = DIAS_ES[agora.weekday()]
    return agora.strftime(f"  🕐  HORA ACTUAL:  %H:%M:%S  —  {dia_semana} %d/%m/%Y  ")



# ─────────────────────────────────────────────────
# RUTA DOS FICHEIROS DE AUDIO
# Os audios están gardados en /home/talentos/audios/
# Nomeados correlativamente: audio1.wav, audio2.wav...
# ─────────────────────────────────────────────────
RUTA_AUDIOS = "/home/talentos/audios/"

# ─────────────────────────────────────────────────
# TÁBOA DE ACTIVIDADES DIARIAS
# Cada entrada: (hora, minuto, número_audio, mensaxe)
# ─────────────────────────────────────────────────
ACTIVIDADES = [
    (10,  0,  1, "🏫  SON AS 10:00 H  —  CHEGADA A ASPACE"),
    (10, 30,  2, "🔨  SON AS 10:30 H  —  ACTIVIDADE NO TALLER"),
    (11, 20,  3, "☕  SON AS 11:20 H  —  DESCANSO"),
    (12, 45,  4, "🍽️  SON AS 12:45 H  —  COMEDOR"),
    (13, 30,  5, "🦷  SON AS 13:30 H  —  LAVAR OS DENTES"),
    (14,  0,  6, "😴  SON AS 14:00 H  —  TEMPO LIBRE"),
    (15,  0,  7, "💪  SON AS 15:00 H  —  ACTIVIDADE"),
    (16, 30,  8, "🧥  SON AS 16:30 H  —  HAI QUE POÑER A CHAQUETA"),
    (17, 10,  9, "🚌  SON AS 17:10 H  —  SAÍDA"),
]

# ─────────────────────────────────────────────────
# NÚMERO DE FILA EN QUE ESTÁ O RELOXO NA PANTALLA
# Cabeceira ocupa: liña baleira(1) + ═══(2) + título(3)
#   + subtítulo(4) + RPI(5) + ═══(6) + liña baleira(7)
# Reloxo: fila 8
# ─────────────────────────────────────────────────
FILA_RELOXO = 8

# ─────────────────────────────────────────────────
# FUNCIÓN: Ocultar / mostrar o cursor do terminal
# ─────────────────────────────────────────────────
def ocultar_cursor():
    sys.stdout.write("\033[?25l")
    sys.stdout.flush()

def mostrar_cursor():
    sys.stdout.write("\033[?25h")
    sys.stdout.flush()

# ─────────────────────────────────────────────────
# FUNCIÓN: Escribir texto nunha fila concreta
# sen mover o resto do contido da pantalla
# ─────────────────────────────────────────────────
def escribir_en_fila(fila, texto):
    sys.stdout.write(mover_cursor(fila) + LIMPAR_FIN_LIÑA + texto)
    sys.stdout.flush()

# ─────────────────────────────────────────────────
# FUNCIÓN: Debuxar toda a pantalla de unha vez
# Só se chama ao inicio e cando cambia algo
# (actividade activa ou nova alerta)
# Usa un único write() para evitar parpadeo
# ─────────────────────────────────────────────────
def debuxar_pantalla_completa(agora, ultima_alerta):
    hora   = agora.hour
    minuto = agora.minute
    ancho  = 70

    buf = []

    # Limpar pantalla e situar cursor en (1,1)
    buf.append("\033[2J\033[H")

    # ── Cabeceira (filas 1-7) ──
    liña = "═" * ancho
    buf.append(f"{FONDO_NEGRO}{COR_AMARELO}{NEGRITA}\n")
    buf.append(f"  {liña}\n")
    buf.append(f"  {'AI TEMPO':^{ancho}}\n")
    buf.append(f"  {'Sistema de Xestión de Actividades Diarias':^{ancho}}\n")
    buf.append(f"  {'Raspberry Pi 5':^{ancho}}\n")
    buf.append(f"  {liña}\n")
    buf.append(f"{RESTABLECER}\n")

    # ── Reloxo (fila 8) ──
    hora_str = formato_data(agora)
    buf.append(f"{FONDO_NEGRO}{COR_CIAN}{NEGRITA}{hora_str}{RESTABLECER}\n")
    buf.append("\n")

    # ── Táboa de actividades ──
    buf.append(f"{FONDO_NEGRO}{COR_AMARELO}{NEGRITA}  {'PLANIFICACIÓN DO DÍA':^66}{RESTABLECER}\n")
    buf.append(f"{FONDO_NEGRO}{COR_AMARELO}  {'─' * 66}{RESTABLECER}\n")

    activa = _calcular_activa(hora, minuto)

    for i, (h, m, num, msg) in enumerate(ACTIVIDADES):
        hora_fmt = f"{h:02d}:{m:02d}"
        if i == activa:
            buf.append(
                f"{FONDO_NEGRO}{COR_VERMELLO}{NEGRITA}"
                f"  ▶  {hora_fmt}  {msg:<55}"
                f"{RESTABLECER}\n"
            )
        else:
            buf.append(
                f"{FONDO_NEGRO}\033[37m"
                f"     {hora_fmt}  {msg:<55}"
                f"{RESTABLECER}\n"
            )

    buf.append(f"{FONDO_NEGRO}{COR_AMARELO}  {'─' * 66}{RESTABLECER}\n")
    buf.append("\n")

    # ── Zona de alerta ──
    if ultima_alerta:
        buf.append(_texto_alerta(ultima_alerta))
    else:
        buf.append(
            f"{FONDO_NEGRO}  {'Agardando próxima actividade...':^66}{RESTABLECER}\n"
        )

    # Un único write() → sen parpadeo
    sys.stdout.write("".join(buf))
    sys.stdout.flush()

# ─────────────────────────────────────────────────
# FUNCIÓN: Actualizar SÓ a liña do reloxo
# Chámase cada segundo; non toca o resto da pantalla
# Isto é o que elimina o parpadeo visible
# ─────────────────────────────────────────────────
def actualizar_reloxo(agora):
    hora_str = formato_data(agora)
    escribir_en_fila(
        FILA_RELOXO,
        f"{FONDO_NEGRO}{COR_CIAN}{NEGRITA}{hora_str}{RESTABLECER}"
    )

# ─────────────────────────────────────────────────
# FUNCIÓN: Calcular cal é a actividade activa agora
# ─────────────────────────────────────────────────
def _calcular_activa(hora, minuto):
    activa = None
    for i, (h, m, _, _) in enumerate(ACTIVIDADES):
        if hora > h or (hora == h and minuto >= m):
            activa = i
    return activa

# ─────────────────────────────────────────────────
# FUNCIÓN: Xerar o texto da caixa de alerta
# Devolve un string listo para imprimir
# ─────────────────────────────────────────────────
def _texto_alerta(mensaxe):
    ancho   = 66
    borde   = "█" * (ancho + 4)
    espacio = "█" + " " * (ancho + 2) + "█"

    palabras  = mensaxe.strip().split()
    liñas     = []
    liña_temp = ""
    for palabra in palabras:
        if len(liña_temp) + len(palabra) + 1 <= ancho:
            liña_temp = (liña_temp + " " + palabra).strip()
        else:
            liñas.append(liña_temp)
            liña_temp = palabra
    if liña_temp:
        liñas.append(liña_temp)

    partes = [f"{FONDO_NEGRO}{COR_VERMELLO}{NEGRITA}\n"]
    partes.append(f"  {borde}\n")
    partes.append(f"  {espacio}\n")
    for liña in liñas:
        partes.append(f"  █  {liña:^{ancho}}  █\n")
    partes.append(f"  {espacio}\n")
    partes.append(f"  {borde}\n")
    partes.append(f"{RESTABLECER}\n")
    return "".join(partes)

# ─────────────────────────────────────────────────
# FUNCIÓN: Reproducir o ficheiro de audio
# Usa aplay (ALSA) nun fío separado (non bloqueante)
# ─────────────────────────────────────────────────
def reproducir_audio(numero_audio):
    ruta_completa = os.path.join(RUTA_AUDIOS, f"audio{numero_audio}.wav")

    def _reproducir():
        if os.path.exists(ruta_completa):
            try:
                subprocess.run(
                    ["aplay", ruta_completa],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL
                )
            except FileNotFoundError:
                try:
                    subprocess.run(
                        ["paplay", ruta_completa],
                        stdout=subprocess.DEVNULL,
                        stderr=subprocess.DEVNULL
                    )
                except Exception:
                    pass

    fío_audio = threading.Thread(target=_reproducir, daemon=True)
    fío_audio.start()

# ─────────────────────────────────────────────────
# FUNCIÓN: Comprobar se toca disparar un aviso
# Só dispara no segundo 0 de cada actividade
# ─────────────────────────────────────────────────
def comprobar_aviso(hora, minuto, segundo):
    if segundo != 0:
        return None
    for (h, m, num, msg) in ACTIVIDADES:
        if hora == h and minuto == m:
            return (num, msg)
    return None

# ─────────────────────────────────────────────────
# FUNCIÓN PRINCIPAL
# Estratexia sen parpadeo:
#   1. Debuxar pantalla completa só ao inicio e
#      cando cambia a actividade activa ou a alerta
#   2. Cada segundo: actualizar SÓ a liña do reloxo
#      mediante posicionamento de cursor ANSI
#      → o resto da pantalla non se toca → sen parpadeo
# ─────────────────────────────────────────────────
def main():
    ocultar_cursor()

    ultima_alerta    = None
    ultima_activa    = -1    # Índice da última actividade resaltada
    necesita_redebux = True  # Forzar debuxo completo ao inicio

    try:
        while True:
            agora   = datetime.datetime.now()
            hora    = agora.hour
            minuto  = agora.minute
            segundo = agora.second

            # ── Comprobar se cambiou a actividade activa ──
            activa_agora = _calcular_activa(hora, minuto)
            if activa_agora != ultima_activa:
                ultima_activa    = activa_agora
                necesita_redebux = True

            # ── Comprobar se toca un aviso ──
            aviso = comprobar_aviso(hora, minuto, segundo)
            if aviso:
                num_audio, mensaxe = aviso
                ultima_alerta      = mensaxe
                necesita_redebux   = True   # Redibujar para mostrar a alerta
                reproducir_audio(num_audio)

            # ── Debuxo completo só cando é estrictamente necesario ──
            if necesita_redebux:
                debuxar_pantalla_completa(agora, ultima_alerta)
                necesita_redebux = False
            else:
                # Só actualizamos a liña do reloxo → sen parpadeo
                actualizar_reloxo(agora)

            # Agardamos ata o seguinte segundo,
            # compensando o tempo de execución deste ciclo
            agora_despois = datetime.datetime.now()
            tempo_usado   = agora_despois.microsecond / 1_000_000
            time.sleep(max(0, 1.0 - tempo_usado))

    except KeyboardInterrupt:
        # Saída limpa ao premer Ctrl+C
        os.system("clear")
        print(f"\n{COR_AMARELO}{NEGRITA}  AI TEMPO finalizado. Até logo!{RESTABLECER}\n")

    finally:
        mostrar_cursor()

# ─────────────────────────────────────────────────
# PUNTO DE ENTRADA DO PROGRAMA
# ─────────────────────────────────────────────────
if __name__ == "__main__":
    main()
