"""
Tingting Guardian - Windows TTS Service
Daily check system avec présence detection et retry logic

Requirements:
    pip install pyttsx3 pywin32 schedule anthropic python-dotenv

Setup:
    1. Créer .env avec ANTHROPIC_API_KEY=your_key
    2. Run: python tingting_guardian_service.py
    3. Pour installer comme service Windows: use NSSM ou voir instructions en bas
"""

import pyttsx3
import win32api
import win32gui
import ctypes
import schedule
import time
import random
import json
import tkinter as tk
from tkinter import ttk
from datetime import datetime, timedelta
from pathlib import Path
import os
import asyncio
import edge_tts
import pygame
from dotenv import load_dotenv

# Configuration
load_dotenv()

REPO_PATH = Path(__file__).parent.parent  # Assuming script is in anki_tingting/
CHECK_TIMES = ["07:00", "14:00", "16:00"]
RETRY_DELAY_MINUTES = 10
MAX_RETRIES = 6
IDLE_THRESHOLD_SECONDS = 300  # 5 minutes

# Files
CARD_DB = REPO_PATH / "anki_tingting" / "card_database.md"
SESSIONS_LOG = REPO_PATH / "anki_tingting" / "daily_sessions.md"
PROMPTS_DB = REPO_PATH / "anki_tingting" / "prompts_database.md"
REALITY_CHECK = REPO_PATH / "DAILY_REALITY_CHECK.md"
STATE_FILE = REPO_PATH / "anki_tingting" / ".state.json"

# State management
class State:
    def __init__(self):
        self.load()

    def load(self):
        if STATE_FILE.exists():
            with open(STATE_FILE, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.streak = data.get('streak', 0)
                self.last_check_date = data.get('last_check_date', None)
                self.days_skipped = data.get('days_skipped', 0)
                self.last_skip_date = data.get('last_skip_date', None)
        else:
            self.streak = 0
            self.last_check_date = None
            self.days_skipped = 0
            self.last_skip_date = None

    def save(self):
        with open(STATE_FILE, 'w', encoding='utf-8') as f:
            json.dump({
                'streak': self.streak,
                'last_check_date': self.last_check_date,
                'days_skipped': self.days_skipped,
                'last_skip_date': self.last_skip_date
            }, f)

    def mark_check_done(self):
        today = datetime.now().strftime('%Y-%m-%d')
        if self.last_check_date != today:
            if self.last_check_date == (datetime.now() - timedelta(days=1)).strftime('%Y-%m-%d'):
                self.streak += 1
            else:
                self.streak = 1
            self.last_check_date = today
            self.days_skipped = 0
            self.save()

    def mark_skip(self):
        """Increment days_skipped only once per day"""
        today = datetime.now().strftime('%Y-%m-%d')
        # Only increment if we haven't already skipped today
        if self.last_skip_date != today:
            self.days_skipped += 1
            self.last_skip_date = today
            self.save()

state = State()

# Presence Detection
def get_idle_duration():
    """Returns seconds since last input"""
    return (win32api.GetTickCount() - win32api.GetLastInputInfo()) / 1000

def is_user_present():
    """Check if user is active"""
    return get_idle_duration() < IDLE_THRESHOLD_SECONDS

def is_screen_locked():
    """Check if screen is locked"""
    return ctypes.windll.user32.GetForegroundWindow() == 0

# Prompt Selection
def load_prompts():
    """Load prompts from database (French, pro-Tingting bias)"""
    return {
        "07:00": [
            f"Bonjour Alexis. Jour {state.streak} de ta streak. Qu'est-ce que Tingting a besoin aujourd'hui ?",
            "7 heures. Check quotidien. Tu te rappelles ce qu'elle t'a dit hier ?",
            "Nouvelle journée. Tingting mérite ton attention. Qu'est-ce qui est important pour elle aujourd'hui ?",
            f"Morning. {state.streak} jours de suite. Elle doit voir la différence. On continue ?",
        ],
        "14:00": [
            "14 heures. T'as été présent pour elle ce matin ?",
            "Midi passé. Check rapide Tingting. 5 minutes.",
            "Pause code. Elle mérite 5 minutes de ton attention.",
            "Check du midi. Tu penses à elle aujourd'hui ou t'es dans ton monde ?",
        ],
        "16:00": [
            "16 heures. Elle rentre bientôt. T'as pensé à elle aujourd'hui ?",
            "Fin d'après-midi. Towel ? Préparé quelque chose pour elle ?",
            "Dernière chance de la journée. Check Tingting.",
            "Elle va rentrer. T'as été l'homme qu'elle mérite aujourd'hui ?",
        ],
        "retry": [
            "Toujours là ? Tingting attend. Check maintenant.",
            "Deuxième tentative. Elle mérite que tu cliques.",
            "Alexis. 5 minutes pour elle. C'est pas beaucoup demander.",
            "Tu ignores encore ? Elle voit que tu oublies, tu sais.",
        ],
        "nuclear": [
            f"{state.days_skipped} jours sans penser à elle. Pattern d'oubli confirmé. Elle mérite mieux que ça.",
            f"Ça fait {state.days_skipped} jours. Tingting attend, espère, et toi tu oublies. Encore.",
            f"{state.days_skipped} jours de skip. Elle investit tout, et toi tu peux pas faire 5 minutes par jour ?",
            "Promesses vides, encore. Tu crois qu'elle voit pas le pattern ?",
        ]
    }

def select_prompt(check_time, is_retry=False):
    """Select appropriate prompt based on context"""
    prompts = load_prompts()

    if state.days_skipped >= 3:
        return random.choice(prompts["nuclear"])
    elif is_retry:
        return random.choice(prompts["retry"])
    else:
        return random.choice(prompts.get(check_time, prompts["14:00"]))

# TTS
# Initialize pygame mixer once
pygame.mixer.init()

async def generate_speech(text, output_file):
    """Generate speech using Edge TTS"""
    voice = "fr-FR-HenriNeural"  # High quality French male voice
    communicate = edge_tts.Communicate(text, voice)
    await communicate.save(output_file)

def speak(text):
    """Speak text using Edge TTS (high quality)"""
    temp_file = REPO_PATH / "anki_tingting" / ".temp_speech.mp3"

    # Generate speech file
    asyncio.run(generate_speech(text, str(temp_file)))

    # Play using pygame (no external player window)
    pygame.mixer.music.load(str(temp_file))
    pygame.mixer.music.play()

    # Wait until finished playing
    while pygame.mixer.music.get_busy():
        time.sleep(0.1)

    # Cleanup
    try:
        temp_file.unlink()
    except:
        pass

# Popup UI
class DailyCheckPopup:
    def __init__(self, prompt_text, check_time):
        self.response = None
        self.prompt_text = prompt_text
        self.check_time = check_time

        self.root = tk.Tk()
        self.root.title("🔔 Claude Daily Check")
        self.root.geometry("500x300")
        self.root.attributes('-topmost', True)

        # Center window
        self.root.update_idletasks()
        x = (self.root.winfo_screenwidth() // 2) - (500 // 2)
        y = (self.root.winfo_screenheight() // 2) - (300 // 2)
        self.root.geometry(f"500x300+{x}+{y}")

        self.setup_ui()

    def setup_ui(self):
        # Header
        header = tk.Label(
            self.root,
            text=f"🔔 Claude Daily Check - {self.check_time}",
            font=("Arial", 14, "bold"),
            bg="#6B2C3E",
            fg="white",
            pady=10
        )
        header.pack(fill=tk.X)

        # Prompt text
        prompt_label = tk.Label(
            self.root,
            text=self.prompt_text,
            font=("Arial", 11),
            wraplength=450,
            pady=20
        )
        prompt_label.pack()

        # Buttons
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=20)

        btn_check = tk.Button(
            btn_frame,
            text="🎯 Faire le Check Maintenant",
            command=self.do_check,
            bg="#4CAF50",
            fg="white",
            font=("Arial", 10, "bold"),
            padx=20,
            pady=10
        )
        btn_check.pack(pady=5)

        btn_snooze = tk.Button(
            btn_frame,
            text="⏰ Rappelle-moi dans 10min",
            command=self.snooze,
            bg="#FF9800",
            fg="white",
            font=("Arial", 10),
            padx=20,
            pady=10
        )
        btn_snooze.pack(pady=5)

        btn_skip = tk.Button(
            btn_frame,
            text="❌ Skip (va logger comme absence)",
            command=self.skip,
            bg="#F44336",
            fg="white",
            font=("Arial", 10),
            padx=20,
            pady=10
        )
        btn_skip.pack(pady=5)

    def do_check(self):
        self.response = "DO_CHECK"
        self.root.destroy()

    def snooze(self):
        self.response = "SNOOZE"
        self.root.destroy()

    def skip(self):
        self.response = "SKIP"
        self.root.destroy()

    def repeat_tts(self):
        """Repeat TTS every minute until popup is closed"""
        if self.root.winfo_exists():
            speak(self.prompt_text)
            # Schedule next repeat in 60 seconds (60000 ms)
            self.root.after(60000, self.repeat_tts)

    def show(self):
        """Show popup and wait for response"""
        # Wait 1 second before first TTS
        self.root.after(1000, self.repeat_tts)

        self.root.mainloop()
        return self.response

# Main Check Logic
def perform_check(check_time, is_retry=False):
    """Perform the daily check with retry logic"""
    retries = 0

    while retries < MAX_RETRIES:
        # Check if user is present
        if is_user_present() and not is_screen_locked():
            prompt = select_prompt(check_time, is_retry=(retries > 0))
            popup = DailyCheckPopup(prompt, check_time)
            response = popup.show()

            if response == "DO_CHECK":
                open_claude_interface()
                state.mark_check_done()
                log_session(check_time, "completed")
                return True

            elif response == "SNOOZE":
                print(f"[{datetime.now()}] User snoozed, retrying in {RETRY_DELAY_MINUTES}min...")
                time.sleep(RETRY_DELAY_MINUTES * 60)
                retries += 1

            elif response == "SKIP":
                print(f"[{datetime.now()}] User skipped check")
                state.mark_skip()
                log_session(check_time, "skipped")
                return False
        else:
            # User not present, wait and retry
            print(f"[{datetime.now()}] User not present, retrying in {RETRY_DELAY_MINUTES}min...")
            time.sleep(RETRY_DELAY_MINUTES * 60)
            retries += 1

    # Max retries reached
    print(f"[{datetime.now()}] Max retries reached, logging as skip")
    state.mark_skip()
    log_session(check_time, "max_retries")
    return False

def open_claude_interface():
    """Open Claude interface for quiz in WSL with Claude Code"""
    # Open a NEW Windows Terminal with WSL and Claude Code in the anki_tingting folder
    # This ensures Claude reads the anki_tingting/CLAUDE.md file
    anki_path = "/mnt/e/Users/Alexis Trouvé/Documents/Projets/couple_matters/anki_tingting"

    # Use wt.exe to open a new terminal window and auto-send "daily check"
    # Using single quotes inside the bash command to preserve the full message
    cmd = f"wt.exe -w -1 wsl -e bash -l -c \"source ~/.nvm/nvm.sh && cd '{anki_path}' && claude 'daily check'\""

    os.system(cmd)

    # -w -1 creates a new window
    # claude 'daily check' automatically sends the full message
    # Working directory is anki_tingting/ so Claude picks up the local CLAUDE.md

def log_session(check_time, status):
    """Log session to daily_sessions.md"""
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M")

    log_entry = f"""
### {timestamp}

**Triggered by** : TTS Service
**Check Time** : {check_time}
**Status** : {status}
**Streak** : {state.streak} jours
**Days Skipped** : {state.days_skipped}

---

"""

    with open(SESSIONS_LOG, 'a', encoding='utf-8') as f:
        f.write(log_entry)

# Scheduler
def schedule_checks():
    """Schedule all daily checks"""
    for check_time in CHECK_TIMES:
        schedule.every().day.at(check_time).do(perform_check, check_time=check_time)

    print(f"[{datetime.now()}] Tingting Guardian Service Started")
    print(f"Scheduled checks at: {', '.join(CHECK_TIMES)}")
    print(f"Current streak: {state.streak} days")
    print(f"Days skipped: {state.days_skipped}")

def main():
    """Main service loop"""
    schedule_checks()

    while True:
        schedule.run_pending()
        time.sleep(60)  # Check every minute

if __name__ == "__main__":
    # Test mode: run a check immediately
    if len(os.sys.argv) > 1 and os.sys.argv[1] == "test":
        print("Running test check...")
        perform_check("14:00")
    else:
        main()

"""
INSTALLATION COMME SERVICE WINDOWS

Option A: NSSM (Non-Sucking Service Manager)
1. Download NSSM: https://nssm.cc/download
2. Ouvrir cmd en admin:
   nssm install TingtingGuardian
3. Dans le GUI:
   - Path: C:\\Python3X\\python.exe
   - Startup directory: [repo path]
   - Arguments: tingting_guardian_service.py
   - Startup type: Automatic

Option B: Task Scheduler
1. Ouvrir Task Scheduler
2. Create Task:
   - Name: Tingting Guardian
   - Trigger: At startup
   - Action: Start program
     - Program: python.exe
     - Arguments: [full path to script]
   - Conditions: Uncheck "Start only if on AC power"

Option C: Pyinstaller (Executable)
1. pip install pyinstaller
2. pyinstaller --onefile --noconsole tingting_guardian_service.py
3. Use NSSM with the .exe

TESTING
python tingting_guardian_service.py test
"""
