"""Feasibility probe: finaled permit -> city tax parcel -> Whatcom County assessor page (owner, exemptions, value, sales).

Usage: python3 feasibility/assessor_probe.py   (writes feasibility/raw/assessor_probe.json, caches pages in feasibility/cache/assessor/)
"""
import json, re, html, time, urllib.request, urllib.parse, collections, random, os
P = "https://maps.cob.org/arcgis3/rest/services/Maps/Grp_Land/MapServer/5/query"
UA = {"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/130 Safari/537.36"}
CACHE = "feasibility/cache/assessor"; os.makedirs(CACHE, exist_ok=True)

def get(url, timeout=40):
    return urllib.request.urlopen(urllib.request.Request(url, headers=UA), timeout=timeout).read().decode("utf-8", "replace")

def parcel_by(field, value):
    q = urllib.parse.urlencode({"where": f"{field}='{value}'", "outFields": "PARCEL_CODE,Property_ID,Owner_Name,FullOwnerAddr,OwnerCS,Site_Address,Site_Unit,Exemption_Type_Code,Land_Use_Description,Subdivision_Description,Sum_Appraised_Total_Value,Ownership_URL", "returnGeometry": "false", "f": "json"})
    return [f["attributes"] for f in json.loads(get(P + "?" + q)).get("features", [])]

def flat(s):
    t = re.sub(r"<script.*?</script>|<style.*?</style>", "", s, flags=re.S)
    t = html.unescape(re.sub(r"<[^>]+>", "|", t)); t = re.sub(r"\s+", " ", t)
    return re.sub(r"(\| ?)+", "|", t)

def assessor(prop_id):
    fn = f"{CACHE}/{prop_id}.html"
    if not os.path.exists(fn):
        open(fn, "w").write(get(f"https://property.whatcomcounty.us/propertyaccess/Property.aspx?cid=0&year=2026&prop_id={prop_id}")); time.sleep(1)
    t = flat(open(fn).read())
    out = {}
    m = re.search(r"Owner\|Name:\|(.*?)\|.*?Mailing Address:\|(.*?)\|(.*?)\|.*?Exemptions:\|(.*?)\|", t)
    if m: out.update(owner=m[1].strip(), mail=(m[2] + " " + m[3]).strip(), exemptions=m[4] if "Pay Tax" not in m[4] else "")
    m = re.search(r"\(=\) Market Value:\|=\|(\$[\d,]+)", t); out["market_value"] = m[1] if m else None
    out["improvements"] = re.findall(r"Improvement #\d+:\|(.*?)\|State Code:\|\d+\|([\d.]+) sqft", t)
    m = re.search(r"Year Built:?\|(\d{4})", t); out["year_built"] = m[1] if m else None
    sales = []
    s = t.split("Sales History", 1)[-1].split("Payout Agreement", 1)[0]
    for row in re.finditer(r"\|(\d+)\|(\d\d/\d\d/\d{4})\|([^|]*)\|([^|]*)\|([^|]*)\|([^|]*)\|(?:[^|$]*\|){0,2}?(\$[\d,.]+)", s):
        sales.append(dict(date=row[2], type=row[3], grantor=row[5], grantee=row[6], price=row[7]))
    out["sales"] = sales
    return out

if __name__ == "__main__":
    permits = json.load(open("feasibility/raw/mm_permits_2015plus.json"))
    fin = [p for p in permits if p["STATUS"] == "FINALED" and p["SITE_APN"]]
    random.seed(7)
    by = collections.defaultdict(list)
    for p in fin: by[p["Housing_Type"]].append(p)
    sample = []
    for t, ps in by.items(): sample += random.sample(ps, min(len(ps), 4 if t in ("TOWNHOUSE (ITK)", "DADU", "SFR (ATTACHED)", "AADU", "DUPLEX") else 2))
    res = []
    for p in sample:
        r = dict(permit=p["PERMIT_NO"], type=p["Housing_Type"], addr=p["SITE_ADDR"], apn=p["SITE_APN"], finaled=p["FINALED"], permit_owner=p["OWNER_NAME"])
        try:
            pc = parcel_by("PARCEL_CODE", p["SITE_APN"])
            r["parcels"] = len(pc)
            if pc:
                a = pc[0]; r.update(parcel_owner=a["Owner_Name"], prop_id=a["Property_ID"], land_use=a["Land_Use_Description"], subdiv=a["Subdivision_Description"])
                r["assessor"] = assessor(str(a["Property_ID"]).strip())
        except Exception as e:
            r["error"] = repr(e)
        res.append(r); print(r["type"], r["addr"], "->", r.get("parcel_owner"), "| sales:", len(r.get("assessor", {}).get("sales", [])))
    json.dump(res, open("feasibility/raw/assessor_probe.json", "w"), indent=1)
