"""
PDF generator — matplotlib + Pillow, glass tables, logo watermark 25%.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import numpy as np
from PIL import Image
import io, os, datetime

_HERE = os.path.dirname(os.path.abspath(__file__))
LOGO_PATH = os.path.join(_HERE, '..', 'logo.png')

C_BLACK  = '#0a0a0a'
C_GOLD   = '#F5A623'
C_WHITE  = '#FFFFFF'
C_LGRAY  = '#8892a4'
C_GREEN  = '#16a34a'
C_PURPLE = '#7c3aed'
FONT     = 'DejaVu Sans'

DAY_NAMES = {1:'روز اول',2:'روز دوم',3:'روز سوم',4:'روز چهارم',
             5:'روز پنجم',6:'روز ششم',7:'روز هفتم'}


def _to_jalali(s):
    try:
        d = datetime.datetime.strptime(str(s)[:10], "%Y-%m-%d")
        gy,gm,gd = d.year,d.month,d.day
        g=365*gy+(gy+3)//4-(gy+99)//100+(gy+399)//400
        for i in range(gm-1): g+=[31,28,31,30,31,30,31,31,30,31,30,31][i]
        if gm>2 and((gy%4==0 and gy%100!=0)or gy%400==0): g+=1
        g+=gd; j=g-79
        np_=j//12053; j%=12053
        jy=979+33*np_+4*(j//1461); j%=1461
        if j>=366: jy+=(j-1)//365; j=(j-1)%365
        for i,v in enumerate([31,31,31,31,31,31,30,30,30,30,30,29]):
            if j>=v: j-=v
            else:
                jm,jd=i+1,j+1; break
        else: jm,jd=12,j+1
        fa=str.maketrans('0123456789','۰۱۲۳۴۵۶۷۸۹')
        return f"{jy}/{jm:02d}/{jd:02d}".translate(fa)
    except: return str(s)


def _add_wm(ax):
    try:
        img = Image.open(LOGO_PATH).convert('RGBA')
        arr = np.array(img, dtype=np.float32)
        r,g,b = arr[:,:,0],arr[:,:,1],arr[:,:,2]
        whiteness = (r+g+b)/3
        alpha_mask = np.clip((245-whiteness)/45, 0, 1)
        arr[:,:,3] = (alpha_mask * 255 * 0.25).astype(np.uint8)
        ax.imshow(Image.fromarray(arr.astype(np.uint8)),
                  extent=[0.10,0.90,0.08,0.92], aspect='auto', zorder=2)
    except: pass


def _header(ax, title, sub=None):
    ax.add_patch(patches.Rectangle((0,0.91),1,0.09,fc=C_BLACK,zorder=3))
    ax.add_patch(patches.Rectangle((0,0.908),1,0.004,fc=C_GOLD,zorder=4))
    ax.text(0.5,0.955,title,fontsize=20,ha='center',va='center',
            color=C_WHITE,fontfamily=FONT,fontweight='bold',zorder=5)
    if sub:
        ax.text(0.5,0.922,sub,fontsize=11,ha='center',va='center',
                color=C_GOLD,fontfamily=FONT,zorder=5)


def _footer(ax, pn):
    ax.add_patch(patches.Rectangle((0,0),1,0.06,fc=C_BLACK,zorder=3))
    ax.add_patch(patches.Rectangle((0,0.058),1,0.003,fc=C_GOLD,zorder=4))
    ax.text(0.5,0.026,'MILAD GYM  —  INTELLIGENT COACH',
            fontsize=8,ha='center',va='center',
            color=C_GOLD,fontfamily=FONT,fontweight='bold',zorder=5)
    ax.text(0.95,0.026,str(pn),fontsize=8,ha='right',va='center',
            color=C_LGRAY,fontfamily=FONT,zorder=5)


def _new_page():
    fig = plt.figure(figsize=(8.27,11.69), facecolor='white')
    ax  = fig.add_axes([0,0,1,1])
    ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
    ax.add_patch(patches.Rectangle((0,0),1,1,fc='white',zorder=0))
    _add_wm(ax)
    return fig, ax


def _to_pil(fig):
    buf = io.BytesIO()
    fig.savefig(buf, format='png', dpi=180, bbox_inches='tight',
                facecolor='white', pad_inches=0)
    buf.seek(0)
    img = Image.open(buf).copy()
    plt.close(fig)
    return img


def _pages_to_pdf(pages):
    buf = io.BytesIO()
    rgb = [p.convert('RGB') for p in pages]
    rgb[0].save(buf, format='PDF', save_all=True,
                append_images=rgb[1:], resolution=180)
    return buf.getvalue()


# ── Cover ─────────────────────────────────────────────────────────────────────
def _cover(name):
    fig = plt.figure(figsize=(8.27,11.69), facecolor='white')
    ax  = fig.add_axes([0,0,1,1])
    ax.set_xlim(0,1); ax.set_ylim(0,1); ax.axis('off')
    ax.add_patch(patches.Rectangle((0,0),1,1,fc='white',zorder=0))
    try:
        logo = Image.open(LOGO_PATH).convert('RGBA')
        ax.imshow(logo, extent=[0.05,0.95,0.22,0.98], aspect='auto', zorder=2)
    except: pass
    ax.add_patch(patches.Rectangle((0.08,0.205),0.84,0.003,fc=C_GOLD,zorder=3))
    ax.text(0.5,0.155,name,fontsize=24,ha='center',va='center',
            color='#1a1a2e',fontfamily=FONT,fontweight='bold',zorder=4)
    ax.text(0.5,0.115,'پروفایل اختصاصی ورزشکار',fontsize=13,ha='center',
            va='center',color=C_GOLD,fontfamily=FONT,zorder=4)
    ax.add_patch(patches.Rectangle((0,0),1,0.07,fc=C_BLACK,zorder=3))
    ax.add_patch(patches.Rectangle((0,0.068),1,0.003,fc=C_GOLD,zorder=4))
    ax.text(0.5,0.030,'MILAD GYM  —  INTELLIGENT COACH',
            fontsize=9,ha='center',va='center',
            color=C_GOLD,fontfamily=FONT,fontweight='bold',zorder=5)
    return _to_pil(fig)


# ── Info ──────────────────────────────────────────────────────────────────────
def _info(athlete, pn):
    fig, ax = _new_page()
    _header(ax, 'MILAD GYM', 'مشخصات ورزشکار')
    _footer(ax, pn)

    def v(k, sfx=''):
        val = athlete.get(k)
        if k == 'created_at' and val: return _to_jalali(val)
        return f"{val}{sfx}" if val else '---'

    rows = [('نام کامل', v('full_name')), ('سن', v('age',' سال')),
            ('قد', v('height',' سانتی‌متر')), ('وزن', v('weight',' کیلوگرم')),
            ('شماره تماس', v('phone')), ('اشتراک', v('subscription_days',' روز')),
            ('تاریخ ثبت', v('created_at'))]

    ax.add_patch(patches.FancyBboxPatch((0.05,0.09),0.90,0.80,
        boxstyle="round,pad=0.01",fc=(1,1,1,0.0),ec=C_GOLD,lw=2.5,zorder=3))
    y = 0.830
    for i,(lbl,val) in enumerate(rows):
        alpha = 0.55 if i%2==0 else 0.25
        ax.add_patch(patches.FancyBboxPatch((0.07,y-0.033),0.86,0.052,
            boxstyle="round,pad=0.003",fc=(0.94,0.96,1.0,alpha),ec='none',zorder=4))
        ax.plot([0.07,0.93],[y+0.019,y+0.019],color='#d0d8f0',lw=0.6,zorder=5)
        ax.add_patch(patches.Rectangle((0.07,y-0.033),0.006,0.052,fc=C_GOLD,zorder=5))
        ax.text(0.91,y-0.007,lbl+' :',fontsize=11.5,ha='right',va='center',
                color='#1a1a2e',fontfamily=FONT,fontweight='bold',zorder=6)
        ax.plot([0.52,0.525],[y-0.007,y-0.007],color='#aaaacc',lw=1,zorder=6)
        ax.text(0.50,y-0.007,str(val),fontsize=11.5,ha='right',va='center',
                color='#2d3748',fontfamily=FONT,zorder=6)
        y -= 0.093
    return _to_pil(fig)


# ── Training ──────────────────────────────────────────────────────────────────
def _training(day_num, exercises, pn):
    fig, ax = _new_page()
    day_label = DAY_NAMES.get(day_num, f'روز {day_num}')
    _header(ax, 'برنامه تمرینی', day_label)
    _footer(ax, pn)

    TL=0.05; TR=0.95; TT=0.865; TB=0.09; ROW_H=0.065
    X_ROW=0.88; X_HAR=0.57; X_SET=0.22; X_REP=0.11

    ax.add_patch(patches.FancyBboxPatch((TL,TB),TR-TL,TT-TB,
        boxstyle="round,pad=0.005",fc=(1,1,1,0.0),ec=C_GOLD,lw=2.5,zorder=3))

    HEADER_Y = TT-0.010
    ax.add_patch(patches.Rectangle((TL+0.002,HEADER_Y-0.042),
        TR-TL-0.004,0.050,fc=C_BLACK,zorder=4))
    for x,lbl in [(X_ROW,'ردیف'),(X_HAR,'حرکت'),(X_SET,'ست'),(X_REP,'تکرار')]:
        ax.text(x,HEADER_Y-0.017,lbl,fontsize=11,ha='center',va='center',
                color=C_GOLD,fontfamily=FONT,fontweight='bold',zorder=5)
    sep_y = HEADER_Y-0.044
    ax.plot([TL,TR],[sep_y,sep_y],color=C_GOLD,lw=1.5,zorder=4)

    fa = str.maketrans('0123456789','۰۱۲۳۴۵۶۷۸۹')
    y = sep_y - ROW_H*0.55
    for i, ex in enumerate(exercises):
        if y < TB+0.02: break
        alpha = 0.55 if i%2==0 else 0.25
        ax.add_patch(patches.Rectangle((TL+0.003,y-ROW_H*0.50),
            TR-TL-0.006,ROW_H*0.88,fc=(0.94,0.96,1.0,alpha),zorder=4))
        ax.plot([TL+0.01,TR-0.01],[y+ROW_H*0.43,y+ROW_H*0.43],
                color='#d0d8f0',lw=0.5,zorder=5)
        ax.add_patch(plt.Circle((X_ROW,y-0.005),0.022,
            fc=C_GOLD,ec='#d4890a',lw=1,zorder=6))
        ax.text(X_ROW,y-0.005,str(i+1).translate(fa),fontsize=10,
                ha='center',va='center',color=C_BLACK,
                fontfamily=FONT,fontweight='bold',zorder=7)
        ax.text(X_HAR,y-0.005,ex['exercise_name'],fontsize=11,
                ha='center',va='center',color='#1a1a2e',
                fontfamily=FONT,fontweight='bold',zorder=6)
        ax.add_patch(patches.FancyBboxPatch((X_SET-0.038,y-0.022),0.076,0.037,
            boxstyle="round,pad=0.004",fc='#dcfce7',ec='#16a34a',lw=1.2,zorder=6))
        _sets_disp = '—' if int(ex.get('sets') or 0) == 0 else str(ex['sets'])
        ax.text(X_SET,y-0.004,_sets_disp,fontsize=11,
                ha='center',va='center',color=C_GREEN,
                fontfamily=FONT,fontweight='bold',zorder=7)
        ax.add_patch(patches.FancyBboxPatch((X_REP-0.038,y-0.022),0.076,0.037,
            boxstyle="round,pad=0.004",fc='#ede9fe',ec='#7c3aed',lw=1.2,zorder=6))
        _reps_disp = f"{ex['reps']} دقیقه" if int(ex.get('sets') or 0) == 0 else str(ex['reps'])
        ax.text(X_REP,y-0.004,_reps_disp,fontsize=11,
                ha='center',va='center',color=C_PURPLE,
                fontfamily=FONT,fontweight='bold',zorder=7)
        # سوپرست: براکت قرمز که این حرکت را به حرکت بعدی وصل می‌کند
        if ex.get('superset') and i < len(exercises)-1:
            bx = TR + 0.012
            y1, y2 = y-0.005, y-ROW_H-0.005
            ax.plot([bx,bx],[y1,y2],color='#dc2626',lw=3,zorder=8,
                    solid_capstyle='round')
            ax.plot([bx-0.008,bx],[y1,y1],color='#dc2626',lw=3,zorder=8)
            ax.plot([bx-0.008,bx],[y2,y2],color='#dc2626',lw=3,zorder=8)
            ax.text(bx+0.012,(y1+y2)/2,'سوپر',fontsize=8,rotation=90,
                    ha='center',va='center',color='#dc2626',
                    fontfamily=FONT,fontweight='bold',zorder=8)
        y -= ROW_H
    return _to_pil(fig)


# ── Text (diet/supplement) ────────────────────────────────────────────────────
def _text(title, body, pn):
    fig, ax = _new_page()
    _header(ax, title)
    _footer(ax, pn)
    ax.add_patch(patches.FancyBboxPatch((0.05,0.09),0.90,0.80,
        boxstyle="round,pad=0.01",fc=(1,1,1,0.0),ec=C_GOLD,lw=1.8,zorder=3))
    y = 0.855
    for line in (body or '').split('\n'):
        if y < 0.12: break
        line = line.strip()
        if not line: y -= 0.018; continue
        is_sec = any(line.startswith(k) for k in
            ['صبحانه','ناهار','شام','میان','قبل','پروتئین','کراتین','مولتی','الکار'])
        if is_sec:
            ax.add_patch(patches.FancyBboxPatch((0.07,y-0.025),0.86,0.040,
                boxstyle="round,pad=0.004",fc=(1.0,0.98,0.90,0.75),ec=C_GOLD,lw=0.8,zorder=4))
            ax.add_patch(patches.Rectangle((0.07,y-0.025),0.007,0.040,fc=C_GOLD,zorder=5))
            ax.text(0.91,y-0.005,line,fontsize=11,ha='right',va='center',
                    color='#7a3800',fontfamily=FONT,fontweight='bold',zorder=6)
            y -= 0.052
        else:
            ax.add_patch(patches.FancyBboxPatch((0.07,y-0.020),0.86,0.033,
                boxstyle="round,pad=0.002",fc=(0.94,0.96,1.0,0.45),ec='#d0d8f0',lw=0.4,zorder=4))
            ax.text(0.91,y-0.004,line,fontsize=10.5,ha='right',va='center',
                    color='#2d3748',fontfamily=FONT,zorder=5)
            y -= 0.040
    return _to_pil(fig)


# ── Public API ────────────────────────────────────────────────────────────────
def generate_athlete_pdf(athlete, training_days, diet_text, supplement_text) -> bytes:
    try:
        pages = []
        pages.append(_cover(athlete.get('full_name','---')))
        pages.append(_info(athlete, 2))
        pn = 3
        if training_days:
            for d in sorted(training_days):
                if training_days[d]:
                    pages.append(_training(d, training_days[d], pn)); pn += 1
        if diet_text:
            pages.append(_text('برنامه غذایی', diet_text, pn)); pn += 1
        if supplement_text:
            pages.append(_text('برنامه مکمل', supplement_text, pn))
        return _pages_to_pdf(pages)
    except Exception as e:
        # Fallback
        try:
            from reportlab.pdfgen import canvas as _c
            buf = io.BytesIO()
            c = _c.Canvas(buf)
            c.setFont('Helvetica', 12)
            c.drawString(100, 750, f"Athlete: {athlete.get('full_name','')}")
            c.drawString(100, 730, f"Error: {str(e)[:100]}")
            c.drawString(100, 710, "Run: pip install matplotlib Pillow numpy")
            c.save()
            return buf.getvalue()
        except:
            return b''
