from sqlalchemy.orm import Session
from celery.signals import task_postrun
from src.utils.db import SessionLocal
from src.apps.recommendations.controller import generate_feedback_recommendations  
from src.apps.datasource.models import Datasource
from src.apps.feedback.models import Task
import uuid
from urllib.parse import urlparse
from dateutil.parser import parse as parse_date
import logging

def safe_parse_date(date_str):
    try:
        return parse_date(date_str).isoformat() if date_str else None
    except Exception:
        return None

def safe_string(value, default="Unknown"):
    return str(value).strip() if isinstance(value, str) and value.strip() else default

def safe_rating(value):
    try:
        return float(value)
    except (TypeError, ValueError):
        return 0


def extract_review_details(bright_data):
    if isinstance(bright_data, list):
        reviews = bright_data  
    elif isinstance(bright_data, dict):
        reviews = bright_data.get("data", [])  
    else:
        raise ValueError("Unexpected data format")

    if not reviews or not isinstance(reviews, list):
        raise ValueError("No valid reviews found")

    # Determine data source type: Yelp (Bright) or Google Maps
    # Determine data source type: Yelp (Bright) or Google Maps
    review_sample = reviews[0]
    raw_business_url = None
    source_type = None

    if "place_id" in review_sample:  # Google review structure
        source_type = "google"
        raw_business_url = review_sample.get("input", {}).get("url") or review_sample.get("url")
    elif "business_id" in review_sample:  # Yelp review structure
        source_type = "yelp"
        raw_business_url = review_sample.get("input", {}).get("url")
    else:
        raise ValueError("Invalid review data format or missing business URL")

    #source_type = source_type.lower()
    clean_business_url = raw_business_url

    # Fetch store from DB
    db = SessionLocal()
    datasource_entry = db.query(Datasource).filter(Datasource.url == clean_business_url).order_by(Datasource.created_at.desc()).first()
    db.close()

    if not datasource_entry:
        raise ValueError("Datasource entry not found.")

    store_id = datasource_entry.store_id
    branch_id = datasource_entry.branch_id
    datasource_id = datasource_entry.ds_id
    snapshot_id = datasource_entry.snapshot_id

    # Format and sanitize reviews
    formatted_reviews = []
    for review in reviews:
        if source_type in {"yelp", "Yelp"}:
            name = safe_string(review.get("Review_auther", {}).get("Username"))
            comment = safe_string(review.get("Content"), default="No comment provided Yelp")
            rating = safe_rating(review.get("Rating"))
            date = safe_parse_date(review.get("Date"))

        elif source_type in {"google", "Google"}:
            name = safe_string(review.get("reviewer_name"))
            comment = safe_string(review.get("review"), default="No comment provided Google")
            rating = safe_rating(review.get("review_rating"))
            date = safe_parse_date(review.get("review_date"))

        else:
            continue # skip unknown source types

        formatted_reviews.append({
            "name": name,
            "comment": comment,
            "rating": rating,
            "date": date,
        })

    return {
        "store_id": store_id,
        "branch_id": branch_id,
        "datasource_id": datasource_id,
        "datasource_source": source_type,
        "snapshot_id": snapshot_id,
        "reviews": formatted_reviews,
    }



def create_task_entry(db: Session, celery_job_id: str, store_id: int, branch_id: int, snapshot_id: uuid.UUID, datasource_id: int):
    try:
        task = Task(
            celery_job_id=celery_job_id,
            store_id=store_id,
            branch_id=branch_id,
            snapshot_id=snapshot_id,
            datasource_id=datasource_id,
            task_status="Analyzing"
        )
        db.add(task)

        datasource = db.query(Datasource).filter(Datasource.ds_id == datasource_id).first()
        if datasource:
            datasource.last_fetch_status = "pending"

    except Exception as e:
        db.rollback()
        print(f"[Error] Failed to create task and update datasource status: {str(e)}")
        raise



def update_task_status(celery_job_id: str, status: str):
    db: Session = SessionLocal()
    try:
        task = db.query(Task).filter(Task.celery_job_id == celery_job_id).first()

        if task:
            task.task_status = status
            datasource = db.query(Datasource).filter(Datasource.ds_id == task.datasource_id).first()
            if datasource:
                datasource.last_fetch_status = status
            
            db.commit()
            return task.branch_id, task.datasource_id

        return None, None

    except Exception as e:
        db.rollback()
        print(f"[Error] Failed to update task and datasource status: {str(e)}")
        return None, None

    finally:
        db.close()



# Setup logging to use the INFO level
logging.basicConfig(level=logging.DEBUG)

def generate_recommendations_task(branch_id: int):
    """
    Celery task to generate and store recommendations for a branch.
    """
    db: Session = SessionLocal()
    try:
        logging.info(f"[Celery Worker] Generating recommendations for branch_id: {branch_id}")
        
        # 📌 Log the input parameters for visibility
        logging.info("\n========== 📢 GENERATE RECOMMENDATIONS INPUT ==========")
        logging.info(f"Branch ID: {branch_id}")
        logging.info("=======================================================\n")
        
        # Generate and store recommendations
        generate_feedback_recommendations(db, branch_id)
        
        db.commit()
        logging.info(f"[Celery Worker] Recommendations generated successfully for branch_id: {branch_id}")

    except Exception as e:
        logging.error(f"[Celery Worker] Error generating recommendations: {str(e)}")
        raise  

    finally:
        db.close()


@task_postrun.connect
def task_postrun_handler(sender=None, task_id=None, state=None, **kwargs):
    # Skip postrun handling for child tasks
    if not sender or sender.name != "src.utils.celery_worker.process_csv_review_data":
        return
    db: Session = SessionLocal()
    try:
        print(f"[Celery] Post-run handler for parent task_id={task_id}, state={state}")
        
        if state == "FAILURE":
            update_task_status(task_id, "failed")

    except Exception as e:
        print(f"[Error] Failed in task_postrun_handler: {str(e)}")
    finally:
        db.close()
