#!/usr/bin/env python3
import argparse,csv,subprocess,sys
from pathlib import Path
from urllib.parse import urlparse

A=Path("/home/bowerybay/public_html/wilgus-automation")
IMG=Path("/home/bowerybay/public_html/wilgus-images/WILGUS")
OUT=Path("/home/bowerybay/public_html/wilgus-videos-vertical-wilgus")
AS=A/"wilgus-v9-assets"
CAT=A/"wilgus-meta-hotel-catalog.csv"
IMS=A/"meta-hotel-images.csv"
REG="/usr/share/fonts/truetype/liberation/LiberationSerif-Regular.ttf"
BOLD="/usr/share/fonts/truetype/liberation/LiberationSerif-Bold.ttf"
ITAL="/usr/share/fonts/truetype/liberation/LiberationSerif-Italic.ttf"
NAVY="0x0E2A5A"; ORANGE="0xF04A00"; CREAM="0xF8F4EC"

def die(x): print("ERROR:",x,file=sys.stderr); sys.exit(1)
def esc(x): return str(x).replace("\\",r"\\").replace(":",r"\:").replace("'",r"\'").replace("%",r"\%")
def table(p,k):
    with p.open("r",encoding="utf-8-sig",newline="") as f:return {r[k].strip():r for r in csv.DictReader(f)}
def n(v):
    s=str(v).strip()
    try:
        x=float(s); return str(int(x)) if x.is_integer() else s
    except:return s
def pic(pid,u):
    p=IMG/pid/Path(urlparse(u).path).name
    if not p.is_file():die(f"{pid}: missing {p}")
    return p

def make(pid,c,m):
    address=c.get("address.addr1","").strip()
    city=(c.get("address.city","").strip() or c.get("neighborhood[0]","").strip()).upper()
    state=c.get("address.region","").strip().upper()
    loc=f"{city}, {state}" if state else city
    beds=n(c.get("custom_number_0","")); baths=n(c.get("custom_number_1","")); sleeps=n(c.get("custom_number_2",""))
    if not all([address,city,beds,baths,sleeps]):die(f"{pid}: incomplete catalog data")
    ps=[pic(pid,m.get(f"image[{j}].url","").strip()) for j in range(6)]
    OUT.mkdir(parents=True,exist_ok=True)
    o=OUT/f"{pid}.mp4"
    if o.exists():
        print("SKIP:",o); return
    td=OUT/".text"; td.mkdir(exist_ok=True)
    af=td/f"{pid}-a.txt"; lf=td/f"{pid}-l.txt"
    af.write_text(address,encoding="utf-8"); lf.write_text(loc,encoding="utf-8")
    aq=str(af).replace(":",r"\:"); lq=str(lf).replace(":",r"\:")

    ins=[]
    for p in ps:ins+=["-loop","1","-t","2","-i",str(p)]
    fixed=["wilgus-v9-sky.jpg","wilgus-v8-beach-fade.jpg","icon-bed.png","icon-bath.png","icon-sleeps.png","wilgus-logo.png"]
    for x in fixed:ins+=["-loop","1","-t","10","-i",str(AS/x)]

    f=[]
    for j in range(6):
        f.append(f"[{j}:v]scale=1080:530:force_original_aspect_ratio=increase,crop=1080:530,setsar=1,format=yuv420p[p{j}]")
    f += [
      "[p0][p1]xfade=transition=fade:duration=0.4:offset=1.6[x1]",
      "[x1][p2]xfade=transition=fade:duration=0.4:offset=3.2[x2]",
      "[x2][p3]xfade=transition=fade:duration=0.4:offset=4.8[x3]",
      "[x3][p4]xfade=transition=fade:duration=0.4:offset=6.4[x4]",
      "[x4][p5]xfade=transition=fade:duration=0.4:offset=8.0[photos]",
      f"color=c={CREAM}:s=1080x1920:d=10[bg]",
      "[6:v]scale=1080:470[h]","[7:v]scale=1080:430[foot]",
      "[8:v]scale=70:-1[bed]","[9:v]scale=70:-1[bath]","[10:v]scale=75:-1[sleep]","[11:v]scale=300:-1[logo]",
      "[bg][h]overlay=0:0[a]","[a][photos]overlay=0:470[b]","[b][foot]overlay=0:1490[c]",
      "[c][bed]overlay=105:1050[d]","[d][bath]overlay=405:1050[e]","[e][sleep]overlay=755:1050[g]"
    ]
    draw=(
      f"[g]"
      f"drawtext=fontfile='{ITAL}':text='Find Your Place at the':fontcolor={NAVY}:fontsize=58:x=(w-text_w)/2:y=235,"
      f"drawtext=fontfile='{ITAL}':text='Beach':fontcolor={ORANGE}:fontsize=58:x=(w-text_w)/2:y=295,"
      f"drawtext=fontfile='{BOLD}':text='VACATION RENTALS':fontcolor={NAVY}:fontsize=27:x=(w-text_w)/2:y=380,"
      f"drawtext=fontfile='{BOLD}':text='{esc(beds)}':fontcolor={NAVY}:fontsize=54:x=205:y=1060,"
      f"drawtext=fontfile='{REG}':text='Bedrooms':fontcolor={NAVY}:fontsize=31:x=125:y=1120,"
      f"drawbox=x=330:y=1055:w=2:h=95:color={ORANGE}:t=fill,"
      f"drawtext=fontfile='{BOLD}':text='{esc(baths)}':fontcolor={NAVY}:fontsize=54:x=485:y=1060,"
      f"drawtext=fontfile='{REG}':text='Bathrooms':fontcolor={NAVY}:fontsize=31:x=405:y=1120,"
      f"drawbox=x=680:y=1055:w=2:h=95:color={ORANGE}:t=fill,"
      f"drawtext=fontfile='{BOLD}':text='{esc(sleeps)}':fontcolor={NAVY}:fontsize=54:x=845:y=1060,"
      f"drawtext=fontfile='{REG}':text='Sleeps':fontcolor={NAVY}:fontsize=31:x=790:y=1120,"
      f"drawbox=x=75:y=1180:w=930:h=2:color={ORANGE}:t=fill,"
      f"drawtext=fontfile='{BOLD}':textfile='{aq}':fontcolor={NAVY}:fontsize=40:x=(w-text_w)/2:y=1208,"
      f"drawtext=fontfile='{REG}':textfile='{lq}':fontcolor={NAVY}:fontsize=27:x=(w-text_w)/2:y=1265,"
      f"drawbox=x=75:y=1315:w=930:h=2:color={ORANGE}:t=fill,"
      f"drawtext=fontfile='{ITAL}':text='Stay for days. Remember for years.':fontcolor={NAVY}:fontsize=40:x=(w-text_w)/2:y=1350[base];"
      f"[base][logo]overlay=(W-w)/2:1390[mid];"
      f"[mid]drawtext=fontfile='{BOLD}':text='wilgusassociates.com':fontcolor={NAVY}:fontsize=31:x=(w-text_w)/2:y=1525[out]"
    )
    f.append(draw)
    cmd=["ffmpeg","-y",*ins,"-filter_complex",";".join(f),"-map","[out]","-t","10","-r","30","-c:v","libx264","-crf","20","-preset","medium","-pix_fmt","yuv420p","-movflags","+faststart",str(o)]
    print(f"{pid}: {address} | {loc} | {beds} bed | {baths} bath | sleeps {sleeps}")
    subprocess.run(cmd,check=True)
    af.unlink(missing_ok=True);lf.unlink(missing_ok=True)
    print("DONE:",o)

def main():
    req=[CAT,IMS]+[AS/x for x in ["wilgus-v9-sky.jpg","wilgus-v8-beach-fade.jpg","icon-bed.png","icon-bath.png","icon-sleeps.png","wilgus-logo.png"]]
    for p in req:
        if not p.is_file():die(f"missing {p}")
    a=argparse.ArgumentParser();a.add_argument("property_id");q=a.parse_args()
    c=table(CAT,"id");m=table(IMS,"hotel_id")
    ids=sorted(set(c)&set(m)) if q.property_id.lower()=="all" else [q.property_id.strip()]
    print(f"Generating {len(ids)} properties into {OUT}")
    for pid in ids:
        if pid not in c or pid not in m:die(f"{pid}: not in both CSVs")
        make(pid,c[pid],m[pid])
if __name__=="__main__":main()
