from datetime import datetime, timezone
from dateutil import parser
from pathlib import Path
from .cache import cache
from openai import OpenAI

import os
import requests
import random
import json

OPENAI_API_KEY = "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"

TODOIST_API_TOKEN = "c2233236d19d56128c89ed6b0a9d10a9e7b287f1"

ACCUWEATHER_API_KEY = "YHeMcr9Aa96Goer8CANIB2E6QIbr5Dp0"
LOCATION_KEY = "251518"

# Setup OpenAI client
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
client = OpenAI()

def update_quick_insight():
    job_id = "daily_quick_insight"
    try:
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        # Grab cached news
        news_items = cache.get("top_news_data", [])
        if not news_items:
            raise ValueError("No news data available in cache")

        # Prepare top 10 headlines
        titles = [item["title"] for item in news_items if "title" in item]
        titles_text = "\n".join(f"- {title}" for title in titles)

        messages = [
            {
                "role": "system",
                "content": (
                    "You are a smart assistant that reads all today's headlines and generates one sharp, short insight. Focus on current trends, tech, business, or social issues. Keep it under 40 words."
                )
            },
            {
                "role": "user",
                "content": f"Here are today's headlines:\n{titles_text}\n\nGive me one smart, timely insight."
            }
        ]

        # Request insight from ChatGPT
        response = client.chat.completions.create(
            model="gpt-4",
            messages=messages,
            temperature=0.7
        )

        insight = response.choices[0].message.content.strip()
        cache.set("daily_quick_insight_data", insight)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": insight,
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }

def get_relevant_news_titles():
    job_id = "select_relevant_news"
    try:
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        articles = cache.get("top_news_data", [])
        if not articles:
            raise ValueError("No articles found in cache")

        titles = [article.get("title", "") for article in articles if article.get("title")]

        if not titles:
            raise ValueError("No valid titles extracted from articles")

        prompt = (
            "Here are today's news headlines:\n\n"
            + "\n".join(f"- {t}" for t in titles)
            + "\n\nBased on my interests (e.g., AI, technology, programming, games, movies, entertainment), "
              "please pick the 5 most relevant headlines and respond with ONLY a JSON array of strings. "
              "Example format: [\"Title 1\", \"Title 2\", ...]"
        )

        response = client.chat.completions.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": "You are a helpful assistant that filters relevant news."},
                {"role": "user", "content": prompt}
            ],
            temperature=0.7
        )

        raw_output = response.choices[0].message.content.strip()

        # Try to parse the response as JSON
        try:
            selected_titles = json.loads(raw_output)
            if not isinstance(selected_titles, list):
                raise ValueError("Parsed output is not a list.")
        except Exception as parse_err:
            raise ValueError(f"Failed to parse response as JSON: {parse_err}\nResponse: {raw_output}")

        cache.set("select_relevant_news_data", selected_titles)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": selected_titles
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e)
        }

def update_news():
    job_id = "top_news"
    try:
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        today = datetime.now().date().isoformat()

        response = requests.get(
            "https://newsapi.org/v2/everything",
            params={
                "apiKey": "55678d36d7bd45ea849943ba88dcc899",
                "language": "en",
                "sortBy": "publishedAt",
                "pageSize": 100,
                "q": "*"  # Using a dash to match all articles (NewsAPI requires a `q`)
            }
        )

        if response.status_code != 200:
            raise Exception(f"NewsAPI error: {response.status_code} - {response.text}")

        data = response.json()
        articles = data.get("articles", [])

        if not articles:
            raise ValueError("No news articles found for today")

        cache.set("top_news_data", articles)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": articles
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }

def generate_tts(text, filename):
    # Ensure /audio directory exists
    output_dir = "audio"
    os.makedirs(output_dir, exist_ok=True)

    # Full path to output file
    output_path = os.path.join(output_dir, f"{filename}.wav")

    url = "http://192.168.70.5:8880/v1/audio/speech"
    headers = {
        "accept": "application/json",
        "x-raw-response": "test",
        "Content-Type": "application/json",
    }
    payload = {
        "model": "kokoro",
        "input": text,
        "voice": "af_heart",
        "response_format": "wav",
        "download_format": "wav",
        "speed": 1,
        "return_download_link": True
    }

    r = requests.post(url, headers=headers, json=payload)
    if r.status_code == 200:
        with open(output_path, "wb") as f:
            f.write(r.content)
        print(f"TTS audio saved to {output_path}")
        return output_path
    else:
        raise Exception(f"Failed to generate TTS. Status code: {r.status_code}")

def update_morning_briefing_transcript():
    job_id = "morning_briefing_transcript"
    try:
        # Mark job as running
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        # Load all required data from cache
        tasks = cache.get("daily_tasks_data", [])
        forecast = cache.get("daily_forecast_data", {})
        dressing_advice = cache.get("daily_dressing_advice_data", "")

        if not tasks or not forecast or not dressing_advice:
            raise ValueError("Missing required data in cache")

        # Extract forecast details
        date_str = forecast.get("Date", "")
        date_obj = datetime.fromisoformat(date_str)
        date_formatted = date_obj.strftime("%A, %B %d, %Y")

        temp_min = forecast["Temperature"]["Minimum"]["Value"]
        temp_max = forecast["Temperature"]["Maximum"]["Value"]
        day_phrase = forecast["Day"]["IconPhrase"]
        night_phrase = forecast["Night"]["IconPhrase"]

        # Build input task summary
        task_lines = []
        for task in tasks:
            due_time = task.get("due", {}).get("datetime")
            task_time = ""
            if due_time:
                try:
                    dt_obj = datetime.fromisoformat(due_time.replace("Z", "+00:00"))
                    task_time = dt_obj.strftime("%H:%M")
                    task_lines.append(f"- At {task_time}, {task['content']}.")
                except Exception:
                    task_lines.append(f"- {task['content']} (time format error).")
            else:
                task_lines.append(f"- {task['content']} (no specific time).")
        tasks_summary = "\n".join(task_lines)

        # Construct the GPT prompt
        prompt = (
            f"Today is {date_formatted}.\n\n"
            f"Here are the tasks for today:\n{tasks_summary}\n\n"
            f"The weather today will be {day_phrase} during the day and {night_phrase} at night. "
            f"Temperatures range from {temp_min}°C to {temp_max}°C.\n\n"
            f"Clothing advice: {dressing_advice}\n\n"
            f"Write a friendly and concise morning briefing script in natural spoken English. "
            f"Start with a brief greeting and mention the date. Then summarize the tasks, the weather, and the clothing advice. "
            f"Make the tone encouraging and warm, as if you're helping someone start their day."
        )

        # Send to GPT
        chat_response = client.chat.completions.create(
            model="gpt-4o",
            messages=[
                {"role": "system", "content": "You are a helpful assistant that creates a morning briefing."},
                {"role": "system", "content": "Your name is Eira and the users name is Collin. Start your briefing off with a variation on 'Hey Eira here'."},
                {
                    "role": "system",
                    "content": (
                        "You are a helpful assistant that writes a spoken transcript for a daily morning briefing. "
                        "The transcript must be suitable for text-to-speech. Use complete sentences and natural language. "
                        "Do not use any special characters or markdown. Avoid line breaks or paragraph breaks—write as a single continuous paragraph."
                    )
                },
                {"role": "user", "content": prompt}
            ]
        )

        transcript = chat_response.choices[0].message.content.strip()

        # Generate TTS Audio File
        success = generate_tts(transcript, "morning_briefing")
        if not success:
            raise RuntimeError("TTS audio generation failed.")

        # Store transcript in cache
        cache.set("morning_briefing_transcript_data", transcript)

        # Mark job as completed
        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": transcript,
        }

    except Exception as e:
        # Mark job as failed
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }

def get_due_datetime(task):
    try:
        dt_str = task.get('due', {}).get('datetime')
        if dt_str:
            dt = parser.isoparse(dt_str)
            if dt.tzinfo is None:
                dt = dt.replace(tzinfo=timezone.utc)
            return dt
    except Exception:
        pass
    return datetime.max.replace(tzinfo=timezone.utc)

def update_daily_tasks(project_id=None, filter_query="today"):
    job_id = "daily_tasks"
    try:
        # Mark job as running
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

       
        headers = {
            "Authorization": f"Bearer {TODOIST_API_TOKEN}"
        }

        params = {}
        if project_id:
            params['project_id'] = project_id
        if filter_query:
            params['filter'] = filter_query

        # Fetch from Todoist API
        response = requests.get("https://api.todoist.com/rest/v2/tasks", headers=headers, params=params)
        
        if response.status_code != 200:
            raise Exception(f"Todoist API error: {response.status_code} - {response.text}")

        data = response.json()


        # Sort tasks by due datetime (handle tasks without due date by putting them last)
        data.sort(key=get_due_datetime)

        # Cache the forecast itself (separately from job status)
        cache.set("daily_tasks_data", data)

        # Mark job as completed
        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": data,
        }

    except Exception as e:
        # Mark job as failed
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }


def update_weather():
    job_id = "daily_weather"
    try:
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        response = requests.get(
            f"http://dataservice.accuweather.com/forecasts/v1/daily/5day/{LOCATION_KEY}",
            params={"apikey": ACCUWEATHER_API_KEY, "metric": "true"},
        )

        if response.status_code != 200:
            raise Exception(f"AccuWeather API error: {response.status_code} - {response.text}")

        data = response.json()

        today_str = datetime.now().date().isoformat()
        daily_forecasts = data.get("DailyForecasts", [])

        today_forecast = next(
            (f for f in daily_forecasts if f.get("Date", "").startswith(today_str)),
            None
        )

        if not today_forecast:
            raise ValueError(f"No forecast found for today ({today_str})")

        cache.set("daily_forecast_data", today_forecast)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": today_forecast,
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }

def update_current_weather():
    job_id = "current_weather"
    try:
        # Mark job as running
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        response = requests.get(
            f"http://dataservice.accuweather.com/currentconditions/v1/{LOCATION_KEY}",
            params={"apikey": ACCUWEATHER_API_KEY, "details": "true"},
        )

        if response.status_code != 200:
            raise Exception(f"AccuWeather API error: {response.status_code} - {response.text}")

        data = response.json()
        if isinstance(data, list):
            data = data[0]  # AccuWeather returns a list

        cache.set("current_weather_data", data)

        # Mark job as completed
        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": data,
        }

    except Exception as e:
        # Mark job as failed
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }

def update_dressing_advice():
    job_id = "daily_dressing_advice"
    try:
        # Mark job as running
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        # Load cached forecast data
        forecast = cache.get("daily_forecast_data")
        if not forecast:
            raise ValueError("No forecast data found in cache.")

        # Extract relevant weather info
        temp_min = forecast.get("Temperature", {}).get("Minimum", {}).get("Value")
        temp_max = forecast.get("Temperature", {}).get("Maximum", {}).get("Value")
        phrase_day = forecast.get("Day", {}).get("IconPhrase", "")
        phrase_night = forecast.get("Night", {}).get("IconPhrase", "")
        date_str = forecast.get("Date", "")

        # Build prompt for GPT
        prompt = (
            f"Today's weather forecast for {date_str}:\n"
            f"- Minimum Temperature: {temp_min}°C\n"
            f"- Maximum Temperature: {temp_max}°C\n"
            f"- Daytime: {phrase_day}\n"
            f"- Nighttime: {phrase_night}\n\n"
            f"Based on this forecast, what clothing should someone wear today? Provide practical and sensible advice."
        )

        # Send prompt to OpenAI
        chat_response = client.chat.completions.create(
            model="gpt-4.1",  # or "gpt-4o" if available
            messages=[
                {"role": "system", "content": "You are a helpful assistant that gives dressing advice based on weather."},
                {"role": "system", "content": "Respond with one paragraph of readable text. No markup or special characters please."},
                {"role": "system", "content": "Don't include actual weather data in your advice."},
                {"role": "user", "content": prompt}
            ]
        )

        advice = chat_response.choices[0].message.content.strip()

        # Cache the advice
        cache.set("daily_dressing_advice_data", advice)

        # Mark job as completed
        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": advice,
        }

    except Exception as e:
        # Mark job as failed
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }


    except Exception as e:
        # Mark job as failed
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }


def update_daily_surprise():
    job_id = "daily_surprise"
    try:
        cache[job_id] = {"status": "running", "started_at": datetime.now().isoformat()}

        # Adjusted path to project root /data/surprises.json
        file_path = Path(__file__).parent.parent / "data" / "surprises.json"
        with open(file_path, "r", encoding="utf-8") as f:
            surprises_data = json.load(f)

        surprises = surprises_data.get("surprises", [])
        if not surprises:
            raise Exception("No surprises found in the JSON file.")

        selected = random.choice(surprises)

        cache.set("daily_surprise_data", selected)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": selected,
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }
        
def refresh_meme():
    job_id = "daily_meme"
    try:
        cache[job_id] = {
            "status": "running",
            "started_at": datetime.now().isoformat(),
        }

        headers = {"User-Agent": "EiraAI/1.0"}
        response = requests.get("https://www.reddit.com/r/dankmemes/top.json?limit=20&t=day", headers=headers)

        if response.status_code != 200:
            raise Exception(f"Reddit API error: {response.status_code} - {response.text}")

        memes = response.json()["data"]["children"]
        meme = random.choice(memes)["data"]
        meme_data = {
            "title": meme["title"],
            "image": meme["url"],
            "permalink": f"https://reddit.com{meme['permalink']}"
        }

        cache.set("daily_meme_data", meme_data)

        cache[job_id] = {
            "status": "completed",
            "last_run": datetime.now().isoformat(),
            "data": meme_data,
        }

    except Exception as e:
        cache[job_id] = {
            "status": "failed",
            "last_run": datetime.now().isoformat(),
            "error": str(e),
        }
