"""
Prospect Skill - Lead import, enrichment, and ICP scoring.
"""

from __future__ import annotations
import csv
import logging
import re
from pathlib import Path
from typing import Optional
from urllib.parse import urlparse

logger = logging.getLogger(__name__)


class ProspectSkill:
    """
    Handles prospect/lead operations:
    - CSV import
    - Domain extraction
    - ICP scoring
    - Basic enrichment
    """

    def __init__(self, config: dict):
        self.config = config
        self.settings = config.get("agents", {}).get("KPRO", {}).get("settings", {})
        self.min_icp_score = self.settings.get("min_icp_score", 60)

    # -------------------------------------------------------------------------
    # Import
    # -------------------------------------------------------------------------

    def import_csv(self, file_path: str) -> list[dict]:
        """
        Import contacts from a CSV file.

        Expected columns (flexible matching):
        - email (required)
        - first_name, last_name
        - company, domain
        - title, phone, linkedin_url

        Returns list of parsed contact dicts.
        """
        path = Path(file_path)
        if not path.exists():
            return [{"error": f"File not found: {file_path}"}]

        contacts = []
        try:
            with open(path, newline="", encoding="utf-8-sig") as f:
                reader = csv.DictReader(f)
                # Normalize headers
                fieldnames = [self._normalize_header(h) for h in reader.fieldnames or []]
                reader.fieldnames = fieldnames

                for row in reader:
                    contact = self._parse_csv_row(row)
                    if contact.get("email"):
                        contacts.append(contact)

            logger.info(f"[ProspectSkill] Imported {len(contacts)} contacts from {file_path}")
            return contacts

        except Exception as e:
            logger.error(f"[ProspectSkill] CSV import error: {e}")
            return [{"error": str(e)}]

    def _normalize_header(self, header: str) -> str:
        """Normalize CSV header to standard field name."""
        header = header.lower().strip().replace(" ", "_").replace("-", "_")
        mappings = {
            "email_address": "email",
            "e_mail": "email",
            "firstname": "first_name",
            "first": "first_name",
            "lastname": "last_name",
            "last": "last_name",
            "company_name": "company",
            "organization": "company",
            "job_title": "title",
            "position": "title",
            "role": "title",
            "phone_number": "phone",
            "mobile": "phone",
            "linkedin": "linkedin_url",
            "linkedin_profile": "linkedin_url",
            "website": "domain",
            "company_website": "domain",
            "url": "domain",
        }
        return mappings.get(header, header)

    def _parse_csv_row(self, row: dict) -> dict:
        """Parse a CSV row into a contact dict."""
        email = row.get("email", "").strip().lower()
        domain = row.get("domain", "")

        # Extract domain from email if not provided
        if not domain and email and "@" in email:
            domain = email.split("@")[1]

        # Extract domain from URL if provided
        if domain and domain.startswith("http"):
            domain = self.extract_domain(domain)

        return {
            "email": email,
            "first_name": row.get("first_name", "").strip(),
            "last_name": row.get("last_name", "").strip(),
            "title": row.get("title", "").strip(),
            "company": row.get("company", "").strip(),
            "domain": domain,
            "phone": row.get("phone", "").strip(),
            "linkedin_url": row.get("linkedin_url", "").strip(),
            "industry": row.get("industry", "").strip(),
            "employee_count": self._parse_int(row.get("employee_count", "")),
        }

    def _parse_int(self, value: str) -> Optional[int]:
        """Parse integer from string, handling ranges like '50-100'."""
        if not value:
            return None
        try:
            # Handle ranges by taking the average
            if "-" in str(value):
                parts = str(value).split("-")
                return int((int(parts[0]) + int(parts[1])) / 2)
            return int(re.sub(r"[^\d]", "", str(value)))
        except (ValueError, IndexError):
            return None

    # -------------------------------------------------------------------------
    # Domain Operations
    # -------------------------------------------------------------------------

    def extract_domain(self, url: str) -> str:
        """Extract domain from URL or email."""
        if not url:
            return ""

        # Handle email addresses
        if "@" in url and not url.startswith("http"):
            return url.split("@")[1].lower()

        # Parse URL
        try:
            if not url.startswith("http"):
                url = "https://" + url
            parsed = urlparse(url)
            domain = parsed.netloc or parsed.path.split("/")[0]
            # Remove www prefix
            domain = re.sub(r"^www\.", "", domain.lower())
            return domain
        except Exception:
            return url.lower()

    def validate_email(self, email: str) -> dict:
        """
        Basic email validation.

        Returns:
            {"valid": bool, "reason": str, "email": str}
        """
        email = email.strip().lower()

        if not email:
            return {"valid": False, "reason": "empty", "email": email}

        # Basic format check
        email_pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
        if not re.match(email_pattern, email):
            return {"valid": False, "reason": "invalid_format", "email": email}

        # Check for common invalid patterns
        invalid_patterns = [
            r"^(test|demo|example|sample|noreply|no-reply|donotreply)@",
            r"@(example|test|localhost)\.",
            r"@.*\.(invalid|test|example)$",
        ]
        for pattern in invalid_patterns:
            if re.search(pattern, email, re.IGNORECASE):
                return {"valid": False, "reason": "disposable_or_test", "email": email}

        return {"valid": True, "reason": "ok", "email": email}

    # -------------------------------------------------------------------------
    # ICP Scoring
    # -------------------------------------------------------------------------

    def score_icp_fit(self, prospect: dict, icp_criteria: dict = None) -> dict:
        """
        Score a prospect against ICP criteria.

        Args:
            prospect: Contact or account data
            icp_criteria: Scoring rules (optional, uses defaults)

        Returns:
            {"score": int, "breakdown": dict, "qualified": bool}
        """
        criteria = icp_criteria or self._default_icp_criteria()
        score = 0
        breakdown = {}

        # Title scoring
        title = (prospect.get("title") or "").lower()
        title_score = self._score_title(title, criteria.get("titles", {}))
        score += title_score
        breakdown["title"] = title_score

        # Company size scoring
        employee_count = prospect.get("employee_count")
        size_score = self._score_company_size(employee_count, criteria.get("company_size", {}))
        score += size_score
        breakdown["company_size"] = size_score

        # Industry scoring
        industry = (prospect.get("industry") or "").lower()
        industry_score = self._score_industry(industry, criteria.get("industries", []))
        score += industry_score
        breakdown["industry"] = industry_score

        # Seniority scoring
        seniority = (prospect.get("seniority") or "").lower()
        seniority_score = self._score_seniority(seniority, title, criteria.get("seniority", {}))
        score += seniority_score
        breakdown["seniority"] = seniority_score

        # Data completeness bonus
        completeness_score = self._score_completeness(prospect)
        score += completeness_score
        breakdown["completeness"] = completeness_score

        # Normalize to 0-100
        max_score = sum([
            criteria.get("titles", {}).get("max_score", 25),
            criteria.get("company_size", {}).get("max_score", 20),
            criteria.get("industries", {}).get("max_score", 15) if isinstance(criteria.get("industries"), dict) else 15,
            criteria.get("seniority", {}).get("max_score", 25),
            15,  # completeness max
        ])
        normalized_score = min(100, int((score / max_score) * 100))

        return {
            "score": normalized_score,
            "breakdown": breakdown,
            "qualified": normalized_score >= self.min_icp_score,
        }

    def _default_icp_criteria(self) -> dict:
        """Default ICP scoring criteria."""
        return {
            "titles": {
                "max_score": 25,
                "keywords": {
                    "ceo": 25, "cto": 25, "cfo": 25, "coo": 25, "cmo": 25, "cro": 25,
                    "chief": 25, "founder": 25, "owner": 25, "president": 25,
                    "vp": 20, "vice president": 20,
                    "head": 18, "director": 18,
                    "senior": 12, "lead": 12, "principal": 12,
                    "manager": 10,
                },
            },
            "company_size": {
                "max_score": 20,
                "ranges": [
                    {"min": 50, "max": 200, "score": 20},
                    {"min": 201, "max": 500, "score": 18},
                    {"min": 501, "max": 1000, "score": 15},
                    {"min": 11, "max": 49, "score": 12},
                    {"min": 1001, "max": 5000, "score": 10},
                ],
            },
            "industries": {
                "max_score": 15,
                "target": ["saas", "software", "technology", "fintech", "b2b"],
            },
            "seniority": {
                "max_score": 25,
                "levels": {
                    "c_level": 25,
                    "vp": 20,
                    "director": 18,
                    "manager": 12,
                    "senior": 10,
                },
            },
        }

    def _score_title(self, title: str, criteria: dict) -> int:
        """Score based on job title."""
        keywords = criteria.get("keywords", {})
        for keyword, score in keywords.items():
            if keyword in title:
                return score
        return 0

    def _score_company_size(self, employee_count: Optional[int], criteria: dict) -> int:
        """Score based on company size."""
        if not employee_count:
            return 0
        for range_def in criteria.get("ranges", []):
            if range_def["min"] <= employee_count <= range_def["max"]:
                return range_def["score"]
        return 0

    def _score_industry(self, industry: str, criteria: list | dict) -> int:
        """Score based on industry."""
        targets = criteria.get("target", []) if isinstance(criteria, dict) else criteria
        for target in targets:
            if target.lower() in industry:
                return 15
        return 0

    def _score_seniority(self, seniority: str, title: str, criteria: dict) -> int:
        """Score based on seniority level."""
        levels = criteria.get("levels", {})

        # Check explicit seniority
        if seniority in levels:
            return levels[seniority]

        # Infer from title
        title_lower = title.lower()
        if any(t in title_lower for t in ["ceo", "cto", "cfo", "coo", "cmo", "chief", "founder"]):
            return levels.get("c_level", 25)
        if "vp" in title_lower or "vice president" in title_lower:
            return levels.get("vp", 20)
        if "director" in title_lower or "head" in title_lower:
            return levels.get("director", 18)
        if "manager" in title_lower:
            return levels.get("manager", 12)
        if "senior" in title_lower or "sr." in title_lower:
            return levels.get("senior", 10)

        return 0

    def _score_completeness(self, prospect: dict) -> int:
        """Score based on data completeness."""
        score = 0
        if prospect.get("email"):
            score += 3
        if prospect.get("first_name") and prospect.get("last_name"):
            score += 3
        if prospect.get("title"):
            score += 3
        if prospect.get("company") or prospect.get("domain"):
            score += 3
        if prospect.get("linkedin_url"):
            score += 2
        if prospect.get("phone"):
            score += 1
        return min(15, score)

    # -------------------------------------------------------------------------
    # Buying Signals (placeholder for enrichment APIs)
    # -------------------------------------------------------------------------

    def detect_buying_signals(self, domain: str) -> list[dict]:
        """
        Detect buying signals for a company.
        This is a placeholder - real implementation would call enrichment APIs.

        Returns list of signals: {"signal": str, "strength": str, "source": str}
        """
        # Placeholder - would integrate with:
        # - News APIs for funding announcements, expansions
        # - Job board APIs for relevant hiring
        # - Tech stack APIs for technology changes
        # - Social APIs for engagement patterns

        signals = []
        logger.info(f"[ProspectSkill] Checking buying signals for {domain} (placeholder)")

        # Return empty list - real implementation would populate this
        return signals

    def enrich_company(self, domain: str) -> dict:
        """
        Enrich company data from domain.
        Placeholder for enrichment API integration.
        """
        logger.info(f"[ProspectSkill] Enriching company: {domain} (placeholder)")

        # Would integrate with Clearbit, Apollo, etc.
        return {
            "domain": domain,
            "enriched": False,
            "message": "Enrichment API not configured",
        }

    def enrich_contact(self, email: str) -> dict:
        """
        Enrich contact data from email.
        Placeholder for enrichment API integration.
        """
        logger.info(f"[ProspectSkill] Enriching contact: {email} (placeholder)")

        # Would integrate with Clearbit, Apollo, Hunter, etc.
        return {
            "email": email,
            "enriched": False,
            "message": "Enrichment API not configured",
        }
