from __future__ import annotations
import json, re, traceback
from pathlib import Path
from typing import Any
try:
    from .connectors import rxnorm, openfda, dailymed, pubmed, url_pdf
    from .connectors.common import utcnow, clean_text
except ImportError:
    from connectors import rxnorm, openfda, dailymed, pubmed, url_pdf
    from connectors.common import utcnow, clean_text

DOMAIN_MAP = {
    "indications and usage":"indications",
    "dosage and administration":"doseByIndication",
    "contraindications":"contraindications",
    "boxed warning":"blackBoxWarnings",
    "warnings and precautions":"clinicalPearls",
    "drug interactions":"majorInteractions",
    "use in specific populations":"clinicalPearls",
    "pregnancy":"pregnancy",
    "lactation":"lactation",
    "renal impairment":"renalDosing",
    "hepatic impairment":"hepaticDosing",
    "storage and handling":"stability",
    "how supplied":"administration",
}

REQUIRED_DOMAINS = [
    "generic","brands","ocrAliases","commonMisspellings","pharmacologicClass","therapeuticClass",
    "indications","doseByIndication","renalDosing","hepaticDosing","hd","crrt","pd","loadingDose",
    "maximumDose","administration","infusionRates","extendedInfusion","ySiteCompatibility","stability",
    "extravasation","vesicantClassification","antidote","tubeAdministration","crushability",
    "hazardousHandling","pregnancy","lactation","blackBoxWarnings","contraindications","monitoring",
    "majorInteractions","highYieldInteractions","therapeuticSubstitutions","formularyAlternatives","clinicalPearls"
]

class ResearchEngine:
    def __init__(self, root: Path):
        self.root=root
        self.cache_dir=root / "data" / "cache"
        self.export_dir=root / "data" / "research_exports"
        self.export_dir.mkdir(parents=True, exist_ok=True)

    def run(self, medication: str, connectors: list[str] | None=None) -> dict[str,Any]:
        selected=connectors or ["rxnorm","dailymed","openfda","pubmed"]
        report={"researchId":f"research_{re.sub(r'[^a-z0-9]+','_',medication.lower()).strip('_')}_{utcnow().replace(':','').replace('-','')}",
                "medication":medication,"createdAt":utcnow(),"sources":[],"draftClaims":[],"identity":{},"errors":[],"gaps":[]}
        concepts=[]
        for name in selected:
            try:
                if name=="rxnorm":
                    src,concepts=rxnorm.research(medication,self.cache_dir); report["sources"].append(src)
                elif name=="dailymed": report["sources"].extend(dailymed.research(medication,self.cache_dir))
                elif name=="openfda": report["sources"].extend(openfda.research(medication,self.cache_dir))
                elif name=="pubmed": report["sources"].append(pubmed.research(medication,self.cache_dir))
            except Exception as exc:
                report["errors"].append({"connector":name,"message":str(exc),"type":type(exc).__name__})
        report["identity"]=self._identity(medication, concepts)
        report["draftClaims"]=self._draft_claims(medication, report["sources"])
        covered={c["field"] for c in report["draftClaims"]}
        covered.update(k for k,v in report["identity"].items() if v)
        report["gaps"]=[d for d in REQUIRED_DOMAINS if d not in covered]
        report["completeness"]={"covered":len(REQUIRED_DOMAINS)-len(report["gaps"]),"total":len(REQUIRED_DOMAINS),"percent":round(100*(len(REQUIRED_DOMAINS)-len(report["gaps"]))/len(REQUIRED_DOMAINS))}
        out=self.export_dir / f"{report['researchId']}.json"
        out.write_text(json.dumps(report,indent=2),encoding="utf-8")
        report["savedTo"]=str(out)
        return report

    def _identity(self, medication: str, concepts: list[dict[str,Any]]):
        names=[c.get("name","") for c in concepts if c.get("name")]
        brands=sorted({n.split('[')[-1].rstrip(']') for n in names if '[' in n})
        rxcuis=sorted({c.get("rxcui","") for c in concepts if c.get("rxcui")})
        return {"generic":medication.strip(),"brands":brands[:30],"rxcuis":rxcuis,"rxnormConcepts":concepts[:100]}

    def _draft_claims(self, medication: str, sources: list[dict[str,Any]]):
        claims=[]; seen=set()
        for src in sources:
            if src.get("connector") not in ("dailymed","openfda"): continue
            for sec in src.get("sections",[]):
                section=clean_text(sec.get("section","")).lower()
                field=next((v for k,v in DOMAIN_MAP.items() if k in section),None)
                text=clean_text(sec.get("text",""))
                if not field or not text: continue
                key=(field,text[:300])
                if key in seen: continue
                seen.add(key)
                claim_id=f"claim_{re.sub(r'[^a-z0-9]+','_',medication.lower()).strip('_')}_{field}_{len(claims)+1:03d}"
                claims.append({
                    "claimId":claim_id,"medicationId":re.sub(r'[^a-z0-9]+','_',medication.lower()).strip('_'),
                    "field":field,"value":text,"population":"","indication":"","route":"","formulation":"",
                    "conditions":{},"applicability":"applicable","validationStatus":"draft","reviewStage":"source_attached",
                    "author":"Automated Research Engine","evidenceIds":[f"ev_{claim_id}"],"consumers":["PhUCKIT"],
                    "automatedExtraction":{"connector":src.get("connector"),"confidence":"section_match","transformation":"whitespace normalization only"},
                    "evidenceDraft":{
                        "evidenceId":f"ev_{claim_id}","claimId":claim_id,"sourceType":src.get("sourceType",""),
                        "citation":src.get("title","") ,"title":src.get("title","") ,"publisher":"",
                        "publicationDate":src.get("publicationDate","") ,"sourceVersion":src.get("sourceVersion","") ,
                        "urlOrId":src.get("url","") ,"accessedAt":src.get("retrievedAt","") ,
                        "locator":{"section":sec.get("section","") ,"subsection":sec.get("subsection","") ,"page":"","table":"","figure":"","recommendation":"","paragraphOrBullet":sec.get("locator","") ,"appendix":"","electronicAnchor":sec.get("sectionCode","")},
                        "claimSupported":text[:500],"supportSummary":f"Automated draft extracted from {sec.get('section','source section')}; owner review required.",
                        "relationship":"supports","verificationStatus":"pending","verifiedBy":"","verifiedAt":"","verificationHistory":[]
                    }
                })
        return claims

    def fetch_url(self,url): return url_pdf.fetch_url(url,self.cache_dir)
    def parse_upload(self,filename,data_b64): return url_pdf.parse_upload(filename,data_b64)
