from __future__ import annotations

import difflib
import re
import urllib.parse
from dataclasses import dataclass
from typing import Optional, Tuple


def _normalize_company_name(name: str) -> str:
    name = name.strip().lower()
    name = re.sub(r"[^a-z0-9]+", " ", name)
    name = re.sub(r"\s+", " ", name).strip()
    return name


@dataclass
class CompanyResolveResult:
    company_name: str
    company_url: Optional[str] = None
    score: float = 0.0
    searched_url: Optional[str] = None


class LinkedInCompanyResolver:
    """
    Resolve a company name into a LinkedIn company page URL using an authenticated browser.
    """

    def resolve(
        self,
        *,
        page,
        company_name: str,
        max_candidates: int = 10,
    ) -> CompanyResolveResult:
        company_name = company_name.strip()
        if not company_name:
            return CompanyResolveResult(company_name=company_name, company_url=None, score=0.0)

        searched_url = (
            "https://www.linkedin.com/search/results/companies/?keywords="
            + urllib.parse.quote(company_name)
        )
        page.goto(searched_url, wait_until="domcontentloaded")

        wanted = _normalize_company_name(company_name)

        # Gather candidate company links.
        anchors = page.locator('a[href*="/company/"]')
        candidates: list[Tuple[str, str]] = []  # (url, label)
        seen = set()
        for i in range(min(200, anchors.count())):
            a = anchors.nth(i)
            try:
                href = a.get_attribute("href") or ""
                if not href or "/company/" not in href:
                    continue
                if href.startswith("http"):
                    url = href
                else:
                    url = "https://www.linkedin.com" + href
                if url in seen:
                    continue
                label = (a.inner_text() or "").strip()
                if not label:
                    continue
                candidates.append((url, label))
                seen.add(url)
                if len(candidates) >= max_candidates:
                    break
            except Exception:
                continue

        best_url: Optional[str] = None
        best_score = 0.0
        for url, label in candidates:
            norm_label = _normalize_company_name(label)
            if not norm_label:
                continue
            if wanted and wanted in norm_label:
                score = 1.0
            else:
                score = difflib.SequenceMatcher(None, wanted, norm_label).ratio()
            if score > best_score:
                best_score = score
                best_url = url

        return CompanyResolveResult(
            company_name=company_name,
            company_url=best_url,
            score=best_score,
            searched_url=searched_url,
        )

