import re
import hashlib
from typing import Optional, Dict, Any, List
from urllib.parse import urlparse
from bs4 import BeautifulSoup
from crawl4ai import AsyncWebCrawler
from ..models.company import CompanyData, ExtractionResult, CrawlStatus


class SwedishCompanyExtractor:
    """Extraherar företagsinformation från svenska webbsidor"""
    
    # Selektorer för svenska företagssidor
    SELECTORS = {
        'company_name': [
            'h1',
            '.company-name',
            '.business-name',
            '[data-testid="company-name"]',
            'meta[property="og:title"]',
            'title'
        ],
        'org_number': [
            '[data-testid="org-number"]',
            '.org-number',
            '.organization-number',
            '.company-id',
            'meta[name="organization-number"]'
        ],
        'email': [
            'a[href^="mailto:"]',
            '.email',
            '[data-testid="email"]',
            'meta[name="email"]'
        ],
        'phone': [
            'a[href^="tel:"]',
            '.phone',
            '.telephone',
            '[data-testid="phone"]',
            'meta[name="phone"]'
        ],
        'address': [
            '.address',
            '.street-address',
            '[data-testid="address"]',
            'meta[name="address"]',
            '.location'
        ],
        'postal_code': [
            '.postal-code',
            '.zip-code',
            '[data-testid="postal-code"]',
            'meta[name="postal-code"]'
        ],
        'city': [
            '.city',
            '.locality',
            '[data-testid="city"]',
            'meta[name="city"]'
        ]
    }
    
    # Regex-mönster för svenska företagsdata
    PATTERNS = {
        'org_number': [
            r'\b\d{6}-\d{4}\b',  # Svenskt organisationsnummer format
            r'\b\d{10}\b',      # 10 siffror utan bindestreck
            r'Org\.?\s*nr\.?\s*[:\s]*(\d{6}-\d{4})',
            r'Organisationsnummer\s*[:\s]*(\d{6}-\d{4})'
        ],
        'phone': [
            r'0\d{2,3}-\d{7,8}',  # Svenskt telefonformat
            r'\+46\s*\d{1,3}\s*\d{3}\s*\d{2}\s*\d{2}',  # Internationellt format
            r'\d{3}-\d{3}\s*\d{2}\s*\d{2}'
        ],
        'postal_code': [
            r'\b\d{3}\s*\d{2}\b',  # Svenskt postnummer
            r'SE-\d{3}\s*\d{2}'
        ],
        'email': [
            r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
        ]
    }
    
    def __init__(self):
        self.confidence_threshold = 0.7
    
    async def extract_from_url(self, url: str, crawler: AsyncWebCrawler) -> ExtractionResult:
        """Extraherar företagsdata från en URL"""
        try:
            result = await crawler.arun(url)
            
            if not result.success:
                return ExtractionResult(
                    success=False,
                    error_message=f"Crawling failed: {result.error_message}"
                )
            
            # Skapa hash av HTML för deduplikation
            html_hash = self._create_html_hash(result.html)
            
            # Extrahera data
            company_data = await self._extract_from_html(result.html, url, html_hash)
            
            return ExtractionResult(
                success=True,
                data=company_data,
                extraction_method="html_parsing",
                confidence_score=company_data.extraction_confidence or 0.0
            )
            
        except Exception as e:
            return ExtractionResult(
                success=False,
                error_message=f"Extraction failed: {str(e)}"
            )
    
    async def _extract_from_html(self, html: str, url: str, html_hash: str) -> CompanyData:
        """Extraherar data från HTML med BeautifulSoup"""
        soup = BeautifulSoup(html, 'html.parser')
        
        extracted_data = {
            'url': url,
            'raw_html_hash': html_hash
        }
        
        # Extrahera med selektorer först
        extracted_fields = {}
        confidence_scores = {}
        
        for field, selectors in self.SELECTORS.items():
            value, confidence = self._extract_with_selectors(soup, selectors)
            if value:
                extracted_fields[field] = value
                confidence_scores[field] = confidence
        
        # Fallback till regex om selektorer misslyckas
        for field, patterns in self.PATTERNS.items():
            if field not in extracted_fields or not extracted_fields[field]:
                value, confidence = self._extract_with_regex(html, patterns)
                if value:
                    extracted_fields[field] = value
                    confidence_scores[field] = confidence
        
        # Rensa och normalisera data
        extracted_fields = self._normalize_data(extracted_fields)
        
        # Beräkna total konfidens
        avg_confidence = sum(confidence_scores.values()) / len(confidence_scores) if confidence_scores else 0.0
        
        # Skapa CompanyData objekt
        return CompanyData(
            **extracted_data,
            **extracted_fields,
            extraction_confidence=avg_confidence
        )
    
    def _extract_with_selectors(self, soup: BeautifulSoup, selectors: List[str]) -> tuple[Optional[str], float]:
        """Försök extrahera data med CSS-selektorer"""
        for selector in selectors:
            elements = soup.select(selector)
            
            for element in elements:
                value = None
                
                if element.name == 'meta':
                    value = element.get('content', '').strip()
                elif element.name == 'a':
                    href = element.get('href', '').strip()
                    if href.startswith(('mailto:', 'tel:')):
                        value = href.replace('mailto:', '').replace('tel:', '').strip()
                    else:
                        value = element.get_text(strip=True)
                else:
                    value = element.get_text(strip=True)
                
                if value and len(value) > 2:  # Undvik tomma eller för korta värden
                    return value, 0.8  # Hög konfidens för selektorer
        
        return None, 0.0
    
    def _extract_with_regex(self, html: str, patterns: List[str]) -> tuple[Optional[str], float]:
        """Försök extrahera data med regex-mönster"""
        for pattern in patterns:
            matches = re.findall(pattern, html, re.IGNORECASE)
            if matches:
                # Ta första matchen och rensa den
                value = matches[0] if isinstance(matches[0], str) else matches[0][0] if isinstance(matches[0], tuple) else str(matches[0])
                value = value.strip()
                
                if len(value) > 2:
                    return value, 0.6  # Lägre konfidens för regex
        
        return None, 0.0
    
    def _normalize_data(self, data: Dict[str, Any]) -> Dict[str, Any]:
        """Normaliserar och rensar extraherad data"""
        normalized = {}
        
        # Rensa telefonnummer
        if 'phone' in data and data['phone']:
            phone = re.sub(r'[^\d+]', '', data['phone'])
            if phone.startswith('00') and len(phone) > 10:
                phone = '+' + phone[2:]
            elif phone.startswith('0') and len(phone) >= 10:
                phone = '+46' + phone[1:]
            normalized['phone'] = phone
        
        # Rensa organisationsnummer
        if 'org_number' in data and data['org_number']:
            org = re.sub(r'[^\d]', '', data['org_number'])
            if len(org) == 10:
                normalized['org_number'] = f"{org[:6]}-{org[6:]}"
            else:
                normalized['org_number'] = org
        
        # Rensa e-post
        if 'email' in data and data['email']:
            email = data['email'].lower().strip()
            if '@' in email:
                normalized['email'] = email
        
        # Rensa postnummer
        if 'postal_code' in data and data['postal_code']:
            postal = re.sub(r'[^\d]', '', data['postal_code'])
            if len(postal) == 5:
                normalized['postal_code'] = f"{postal[:3]} {postal[3:]}"
        
        # Kopiera övriga fält
        for field in ['company_name', 'address', 'city', 'website']:
            if field in data and data[field]:
                value = data[field].strip()
                if value:
                    normalized[field] = value
        
        return normalized
    
    def _create_html_hash(self, html: str) -> str:
        """Skapar hash av HTML-innehåll för deduplikation"""
        return hashlib.md5(html.encode('utf-8')).hexdigest()
