import csv,json,re,sys,collections,statistics,glob
csv.field_size_limit(10**9)
files={"Duval":"nal/Duval/NAL26F202601.csv","St. Johns":"nal/Saint/NAL65F202601.csv","Clay":"nal/Clay/NAL20F202601.csv","Nassau":"nal/Nassau/NAL55F202601.csv","Baker":"nal/Baker/NAL12F202601.csv"}
NINES_ZIPS={"32081","32082","32259","32092","32095","32080","32084","32086","32224","32256","32258","32257","32246","32250","32266","32233","32223","32225","32207","32217"}
ENT=re.compile(r'\b(LLC|L\.L\.C|INC\b|CORP|CO\b|LP\b|LLP|LTD|TRUST|TR\b|TRUSTEE|HOLDINGS|PROPERTIES|PARTNERS|ASSOC|CHURCH|CITY OF|COUNTY|STATE OF|SCHOOL|AUTHORITY|UNITED STATES|BOARD)')
GOV=re.compile(r'\b(CITY OF|COUNTY|STATE OF|SCHOOL BOARD|AUTHORITY|UNITED STATES|JEA\b|DISTRICT|FLORIDA DEPT|DEPARTMENT OF|BOARD OF)')
def grp(uc):
    try: u=int(uc)
    except: return None
    if u==10: return "vacant_commercial"
    if 11<=u<=39: return "commercial_improved"
    if u==40: return "vacant_industrial"
    if 41<=u<=49: return "industrial_improved"
    if u in (3,8): return "multifamily"
    if u==99: return "acreage_unzoned"
    if 50<=u<=69: return "agricultural"
    if u==0: return "vacant_residential"
    if u in (1,2,4,5,6,7,9): return "residential"
    if 70<=u<=79: return "institutional"
    if 80<=u<=89: return "government"
    return "other"
def num(x):
    try: return float(x)
    except: return 0.0
out={}
for county,fn in files.items():
    g=collections.defaultdict(lambda: collections.Counter())
    jvs=collections.defaultdict(list); owners=collections.defaultdict(set)
    n=0
    with open(fn,encoding='latin-1',newline='') as fh:
        r=csv.DictReader(fh)
        for row in r:
            n+=1
            G=grp(row.get("DOR_UC","").strip())
            if not G: continue
            jv=num(row.get("JV")); land=num(row.get("LND_SQFOOT")); own=(row.get("OWN_NAME") or "").upper().strip()
            ost=(row.get("OWN_STATE") or "").strip().upper(); ozip=(row.get("OWN_ZIPCD") or "").strip()[:5]
            pzip=(row.get("PHY_ZIPCD") or "").strip()[:5]
            sy=int(num(row.get("SALE_YR1"))); sp=num(row.get("SALE_PRC1")); q=(row.get("QUAL_CD1") or "").strip()
            isgov=bool(GOV.search(own)); isent=bool(ENT.search(own)) and not isgov
            c=g[G]; c["parcels"]+=1; c["jv_sum"]+=jv
            if isgov: c["gov_owned"]+=1
            else:
                c["private"]+=1
                owners[G].add((own,(row.get("OWN_ADDR1") or "").strip().upper()))
                if isent: c["entity_owned"]+=1
                if ost and ost!="FL": c["out_of_state_owner"]+=1
                if jv>=1_000_000: c["jv_1m_plus"]+=1
                if jv>=5_000_000: c["jv_5m_plus"]+=1
                if 500_000<=jv<5_000_000: c["jv_500k_5m"]+=1
                if sy and sy<=2016: c["held_10y_plus"]+=1
                if not sy: c["no_sale_on_record"]+=1
                if sy>=2024 and q in ("01","1","Q","02","2"): c["sold_2024_plus_qual"]+=1
                if sy>=2024: c["sold_2024_plus"]+=1
                if sy>=2025: c["sold_2025_plus"]+=1
                if land>=87_120: c["land_2ac_plus"]+=1
                if land>=217_800: c["land_5ac_plus"]+=1
                if land>=435_600: c["land_10ac_plus"]+=1
                jvs[G].append(jv)
                if G=="residential":
                    hm=num(row.get("JV_HMSTD"))>0
                    if jv>=1_000_000:
                        c["home_1m_plus"]+=1
                        if not hm: c["home_1m_plus_nonhomestead"]+=1
                        if ost and ost!="FL": c["home_1m_plus_out_of_state"]+=1
                        if pzip in NINES_ZIPS: c["home_1m_plus_nines_zips"]+=1
                        if sy>=2025 and sp>=1_000_000: c["home_1m_plus_bought_2025"]+=1
                        if sy>=2024 and sp>=1_000_000: c["home_1m_plus_bought_2024plus"]+=1
                    if jv>=1_500_000: c["home_1_5m_plus"]+=1
                    if jv>=2_000_000: c["home_2m_plus"]+=1
                    if jv>=750_000: c["home_750k_plus"]+=1
                    if jv>=750_000 and pzip in NINES_ZIPS: c["home_750k_plus_nines_zips"]+=1
    res={}
    for G,c in g.items():
        d=dict(c); d["unique_private_owners"]=len(owners[G])
        if jvs[G]: d["jv_median"]=statistics.median(jvs[G])
        res[G]=d
    res["_rows"]=n
    out[county]=res
    print(county,n,file=sys.stderr)
json.dump(out,open("nal_summary.json","w"),indent=1)
# totals
tot=collections.defaultdict(lambda: collections.Counter())
for county,res in out.items():
    for G,d in res.items():
        if G.startswith("_"): continue
        for k,v in d.items():
            if k!="jv_median": tot[G][k]+=v
for G in ("commercial_improved","vacant_commercial","industrial_improved","vacant_industrial","multifamily","acreage_unzoned","agricultural","residential","vacant_residential"):
    print(G,dict(tot[G]))
