import numpy as np

from sentence_transformers import SentenceTransformer
import warnings
import requests
import os
from dotenv import load_dotenv
import logging

# Load environment variables
load_dotenv()

# Fix NumPy 2.0 compatibility issue
if not hasattr(np, "float_"):
    np.float_ = np.float64

# Suppress NumPy warnings
warnings.filterwarnings("ignore", message=".*np.float_.*")

# Setup logging
logger = logging.getLogger(__name__)


class Embedder:
    def __init__(self):
        self.model = SentenceTransformer("all-mpnet-base-v2")

    def embed(self, text: str):
        try:
            return self.model.encode(text).tolist()
        except Exception as e:
            # Handle any NumPy compatibility issues
            if "np.float_" in str(e):
                # Force conversion to compatible format
                embedding = self.model.encode(text)
                return embedding.astype(np.float64).tolist()
            else:
                raise e

    def embed_with_qdrant(self, text: str):
        """Generate embeddings using local method (Qdrant embedding API not available)"""
        QDRANT_API_URL = os.getenv("QDRANT_API_URL")
        QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")

        if not QDRANT_API_URL or not QDRANT_API_KEY:
            logger.warning("Qdrant API URL or API Key not configured in environment")
            return self.embed(text)

        # For Qdrant Cloud, embedding endpoint might not be available
        # Use local embedding as primary method
        logger.info("Using local embedding instead of Qdrant API")
        return self.embed(text)

    def store_in_qdrant(
        self,
        jobseeker_id: str,
        text: str,
        embedding: list = None,
        country_name: str = "",
        country_header_code: str = "",
    ):
        """Store resume data in Qdrant collection with country information"""
        try:
            if embedding is None:
                embedding = self.embed_with_qdrant(text)

            collection_name = os.getenv("QDRANT_COLLECTION_NAME")
            QDRANT_SEARCH_URL = os.getenv("QDRANT_SEARCH_URL")
            QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")

            if not all([collection_name, QDRANT_SEARCH_URL, QDRANT_API_KEY]):
                logger.warning(
                    "Qdrant configuration not complete in environment variables"
                )
                return False

            url = f"{QDRANT_SEARCH_URL}/{collection_name}/points"
            headers = {
                "api-key": QDRANT_API_KEY,
                "Content-Type": "application/json",
            }

            # Convert string ID to integer for Qdrant compatibility
            try:
                point_id = int(jobseeker_id)
            except ValueError:
                # If jobseeker_id is not a valid integer, use hash
                point_id = hash(jobseeker_id) % (2**32)  # Keep it as 32-bit integer

            point_payload = {
                "points": [
                    {
                        "id": point_id,  # Use integer ID
                        "vector": embedding,
                        "payload": {
                            "resume_id": jobseeker_id,  # Keep original ID in payload
                            "text": text[:1000],  # Limit text size
                            "country_name": country_name,  # Add country name
                            "country_header_code": country_header_code,  # Add country header code
                        },
                    }
                ]
            }

            response = requests.put(url, json=point_payload, headers=headers)
            response.raise_for_status()
            logger.info(f"Successfully stored jobseeker {jobseeker_id} in Qdrant")
            return True

        except Exception as e:
            logger.error(
                f"Error storing in Qdrant for jobseeker {jobseeker_id}: {str(e)}"
            )
            return False

    def store_in_qdrant_with_details(
        self,
        jobseeker_id: str,
        text: str,
        embedding: list = None,
        payload_data: dict = None,
    ):
        """Store resume data in Qdrant collection with detailed payload information"""
        try:
            if embedding is None:
                embedding = self.embed_with_qdrant(text)

            collection_name = os.getenv("QDRANT_COLLECTION_NAME")
            QDRANT_SEARCH_URL = os.getenv("QDRANT_SEARCH_URL")
            QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")

            if not all([collection_name, QDRANT_SEARCH_URL, QDRANT_API_KEY]):
                logger.warning(
                    "Qdrant configuration not complete in environment variables"
                )
                return False

            url = f"{QDRANT_SEARCH_URL}/{collection_name}/points"
            headers = {
                "api-key": QDRANT_API_KEY,
                "Content-Type": "application/json",
            }

            # Convert string ID to integer for Qdrant compatibility
            try:
                point_id = int(jobseeker_id)
            except ValueError:
                # If jobseeker_id is not a valid integer, use hash
                point_id = hash(jobseeker_id) % (2**32)  # Keep it as 32-bit integer

            # Create comprehensive payload
            payload = {
                "resume_id": jobseeker_id,  # Keep original ID in payload
                "text": text[:1000],  # Limit text size for performance
            }

            # Add detailed payload data if provided
            if payload_data:
                payload.update(
                    {
                        "country_name": payload_data.get("country_name", ""),
                        "country_header_code": payload_data.get(
                            "country_header_code", ""
                        ),
                        "email": payload_data.get("email", ""),
                        "first_name": payload_data.get("first_name", ""),
                        "last_name": payload_data.get("last_name", ""),
                        "profile_summary": payload_data.get("profile_summary", "")[
                            :500
                        ],  # Limit size
                        "skills": payload_data.get("skills", [])[
                            :20
                        ],  # Limit to 20 skills max
                        "experience_years": payload_data.get("experience_years", 0),
                        "highest_education": payload_data.get("highest_education", ""),
                        "current_designation": payload_data.get(
                            "current_designation", ""
                        ),
                        "languages": payload_data.get("languages", [])[
                            :10
                        ],  # Limit to 10 languages max
                    }
                )

            point_payload = {
                "points": [
                    {
                        "id": point_id,  # Use integer ID
                        "vector": embedding,
                        "payload": payload,
                    }
                ]
            }

            response = requests.put(url, json=point_payload, headers=headers)
            response.raise_for_status()
            logger.info(
                f"Successfully stored jobseeker {jobseeker_id} in Qdrant with detailed payload"
            )
            return True

        except Exception as e:
            logger.error(
                f"Error storing detailed data in Qdrant for jobseeker {jobseeker_id}: {str(e)}"
            )
            return False

    def search_with_qdrant(self, query: str, top_k: int = 20):
        """Search resumes in Qdrant using vector similarity"""
        try:
            QDRANT_SEARCH_URL = os.getenv("QDRANT_SEARCH_URL")
            QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
            collection_name = os.getenv("QDRANT_COLLECTION_NAME")

            if not all([QDRANT_SEARCH_URL, QDRANT_API_KEY, collection_name]):
                logger.warning(
                    "Qdrant configuration not complete in environment variables"
                )
                return {"result": []}

            # Generate embedding for query
            embedding = self.embed_with_qdrant(query)

            url = f"{QDRANT_SEARCH_URL}/{collection_name}/points/search"
            headers = {
                "api-key": QDRANT_API_KEY,
                "Content-Type": "application/json",
            }
            payload = {"vector": embedding, "top": top_k, "with_payload": True}

            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            return response.json()

        except Exception as e:
            logger.error(f"Error searching Qdrant: {str(e)}")
            return {"result": []}

    def search_filtered_candidates(
        self, query: str, filtered_resume_ids: list, top_k: int = 20
    ):
        """Search specific candidates in Qdrant using vector similarity"""
        try:
            QDRANT_SEARCH_URL = os.getenv("QDRANT_SEARCH_URL")
            QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
            collection_name = os.getenv("QDRANT_COLLECTION_NAME")

            if not all([QDRANT_SEARCH_URL, QDRANT_API_KEY, collection_name]):
                logger.warning(
                    "Qdrant configuration not complete in environment variables"
                )
                return {"result": []}

            if not filtered_resume_ids:
                logger.info("No filtered resume IDs provided for vector search")
                return {"result": []}

            # Generate embedding for query
            embedding = self.embed_with_qdrant(query)

            url = f"{QDRANT_SEARCH_URL}/{collection_name}/points/search"
            headers = {
                "api-key": QDRANT_API_KEY,
                "Content-Type": "application/json",
            }

            # Create filter to search only specific resume IDs
            # We need to convert resume IDs to point IDs for filtering
            point_ids = []
            for resume_id in filtered_resume_ids:
                try:
                    point_id = int(resume_id)
                    point_ids.append(point_id)
                except ValueError:
                    # If resume_id is not a valid integer, use hash (same as in store_in_qdrant)
                    point_id = hash(resume_id) % (2**32)
                    point_ids.append(point_id)

            payload = {
                "vector": embedding,
                "top": top_k,
                "with_payload": True,
                "filter": {
                    "must": [
                        {
                            "key": "resume_id",
                            "match": {
                                "any": filtered_resume_ids  # Filter by resume_id in payload
                            },
                        }
                    ]
                },
            }

            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            result = response.json()

            logger.info(
                f"Vector search on {len(filtered_resume_ids)} filtered candidates returned {len(result.get('result', []))} results"
            )
            return result

        except Exception as e:
            logger.error(f"Error searching filtered candidates in Qdrant: {str(e)}")
            return {"result": []}

    def search_with_filters(self, query: str, filters: dict = None, top_k: int = 20):
        """Search resumes in Qdrant with advanced filtering by skills, country, etc."""
        try:
            QDRANT_SEARCH_URL = os.getenv("QDRANT_SEARCH_URL")
            QDRANT_API_KEY = os.getenv("QDRANT_API_KEY")
            collection_name = os.getenv("QDRANT_COLLECTION_NAME")

            if not all([QDRANT_SEARCH_URL, QDRANT_API_KEY, collection_name]):
                logger.warning(
                    "Qdrant configuration not complete in environment variables"
                )
                return {"result": []}

            # Generate embedding for query
            embedding = self.embed_with_qdrant(query)

            url = f"{QDRANT_SEARCH_URL}/{collection_name}/points/search"
            headers = {
                "api-key": QDRANT_API_KEY,
                "Content-Type": "application/json",
            }

            payload = {"vector": embedding, "top": top_k, "with_payload": True}

            # Build filters if provided
            if filters:
                filter_conditions = []

                # Country filter
                if filters.get("country_header_code"):
                    filter_conditions.append(
                        {
                            "key": "country_header_code",
                            "match": {"value": filters["country_header_code"]},
                        }
                    )

                # Skills filter (any of the specified skills)
                if filters.get("skills") and isinstance(filters["skills"], list):
                    filter_conditions.append(
                        {"key": "skills", "match": {"any": filters["skills"]}}
                    )

                # Education filter
                if filters.get("education"):
                    filter_conditions.append(
                        {
                            "key": "highest_education",
                            "match": {"value": filters["education"]},
                        }
                    )

                # Experience minimum years filter
                if filters.get("min_experience_years"):
                    filter_conditions.append(
                        {
                            "key": "experience_years",
                            "range": {"gte": filters["min_experience_years"]},
                        }
                    )

                if filter_conditions:
                    payload["filter"] = {"must": filter_conditions}

            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            result = response.json()

            logger.info(
                f"Qdrant search with filters returned {len(result.get('result', []))} results"
            )
            return result

        except Exception as e:
            logger.error(f"Error searching with filters in Qdrant: {str(e)}")
            return {"result": []}
