#!/usr/bin/env python3
"""Rebuild Content tab: 3 short rows per bundle (LinkedIn, IG+TK, YouTube Shorts).
Adds Platform Schedule column for cross-posting on different days."""

import json, re, time, urllib.request, urllib.parse
from pathlib import Path

SHEET_ID = "1aCLZMcvLbacFHrZwuTBlgwezVHoAxFNYpmapqN9AVXY"
SHEETS_BASE = "https://sheets.googleapis.com/v4/spreadsheets"
GOOGLE_TOKEN_PATH = Path.home() / ".config/google-workspace-mcp/profiles/emerson-north/tokens.json"
GOOGLE_CREDS_PATH = Path.home() / ".config/google-workspace-mcp/profiles/emerson-north/credentials.json"

def get_access_token():
    tokens = json.loads(GOOGLE_TOKEN_PATH.read_text())
    if tokens.get("expiry"):
        expiry = tokens["expiry"]
        if isinstance(expiry, str):
            from datetime import datetime
            try:
                exp_time = datetime.fromisoformat(expiry.replace("Z", "+00:00")).timestamp()
            except:
                exp_time = 0
        else:
            exp_time = float(expiry)
        if time.time() < exp_time - 60:
            return tokens["token"]
    creds = json.loads(GOOGLE_CREDS_PATH.read_text())
    data = urllib.parse.urlencode({
        "client_id": creds["installed"]["client_id"],
        "client_secret": creds["installed"]["client_secret"],
        "refresh_token": tokens["refresh_token"],
        "grant_type": "refresh_token"
    }).encode()
    req = urllib.request.Request("https://oauth2.googleapis.com/token", data=data, method="POST")
    with urllib.request.urlopen(req) as r:
        return json.loads(r.read())["access_token"]

def sheets_request(method, path, body=None):
    token = get_access_token()
    url = f"{SHEETS_BASE}/{path}"
    data = json.dumps(body).encode() if body else None
    req = urllib.request.Request(url, data=data, method=method)
    req.add_header("Authorization", f"Bearer {token}")
    req.add_header("Content-Type", "application/json")
    with urllib.request.urlopen(req) as r:
        return json.loads(r.read())

def strip_source(text):
    return re.sub(r'\[SOURCE:[^\]]*\]', '', text or '').strip()

def pick_ig_tk_script(bundle_id, linkedin_script, reels_script, tiktok_script):
    """Pick the better of Reels/TikTok scripts for the combined row.
    Use the TikTok version (shorter, punchier) as the primary."""
    return tiktok_script  # TikTok scripts are already punchy and work on Reels too

# Consolidated scripts — 3 per bundle: LinkedIn, IG+TK, YouTube Shorts
# LinkedIn = original LinkedIn A script (most complete)
# IG+TK = TikTok script (punchy, works on both)
# YouTube Shorts = original YouTube Shorts script

BUNDLE_DATA = {
    'short1': {
        'caption': 'The referral slip sitting on your counter? Here\'s what that actually means.\n\n#myotherapy #kidshealth',
        'linkedin_script': strip_source("""[0:00] Amanda at desk, facing camera directly. Clinical but warm setting. No intro, no greeting.
[0:03] 'Braces move teeth. They do not change the swallowing pattern that caused the misalignment in the first place. And that distinction is exactly why your orthodontist gave you the myo referral.'
[0:14] Cut to Amanda gesturing, explaining mechanism.
[0:16] 'At rest, the tongue should sit gently against the roof of the mouth. Lips are closed. Breathing happens through the nose. When a child has a tongue thrust, the tongue pushes forward against the teeth instead. Every swallow. Five hundred to a thousand times per day.'
[0:34] Amanda holds up one finger.
[0:35] 'Braces apply a corrective force for 12, 18, 24 months. The tongue applies a counter-force for every waking hour after the braces come off. This is the primary driver of orthodontic relapse. Teeth shift. Gaps return. The orthodontist sees it.'
[0:52] Cut to graphic or text card: 'Tongue posture influences the muscles surrounding the teeth and jaw.'
[0:57] Amanda back on camera.
[0:58] 'Myofunctional therapy addresses the swallowing mechanics before or during orthodontic treatment, so that when the braces come off, the muscle environment supports the result. The myo referral is not optional context. It is the piece that determines whether the orthodontic result holds.'
[1:18] Slight pause, direct look at camera.
[1:19] 'If your child received an orthodontist referral for myo therapy, the link in the bio has more on what to do with it.'
[1:26] End card: Lasting Language Therapy logo + 'Free Intake Consult | lastinglanguagetherapy.com/myo-referral-welcome-kit'"""),
        'igtk_script': strip_source("""[0:00] Amanda, direct to camera, relaxed energy.
[0:02] 'If you have been sitting on a myo referral from your orthodontist and the main reason you have not booked is that you do not know what you are walking into, this is for you.'
[0:10] Shift posture slightly, more conversational.
[0:11] 'The free intake consult at Lasting Language Therapy looks like this. You come in. We talk through what the orthodontist observed and what the referral actually means for your child\'s orthodontic outcome.'
[0:22] 'Then I do a brief functional assessment. I look at tongue posture, lip closure, swallowing mechanics, and mouth breathing patterns. At rest, the tongue should sit gently against the roof of the mouth. Lips closed. Nose breathing. I check what the actual pattern is.'
[0:35] 'And at the end, you get a plain-language answer. Does your child need myofunctional therapy? If yes, what does it look like? How long? How often?'
[0:42] 'No charge for the first visit. No obligation to continue. Link in bio.'
[0:46] End frame: 'Free Intake Consult | lastinglanguagetherapy.com/myo-referral-welcome-kit'"""),
        'ytshorts_script': strip_source("""[0:00] Amanda facing camera, casual setting. Direct, warm delivery.
[0:02] 'Three reasons orthodontic patients relapse without myo therapy.'
[0:06] 'Number one: tongue thrust. That is 500 to 1,000 repetitions of forward tongue pressure against the teeth every single day. Braces cannot compete with that.'
[0:18] 'Number two: mouth breathing. When a child breathes through the mouth at rest, the tongue drops from the palate. That changes how the jaw develops.'
[0:28] 'Number three: low tongue posture. The tongue acts as a natural retainer when it rests correctly. Without that, teeth drift.'
[0:40] 'Myo therapy addresses all three. If your orthodontist referred your child, this is exactly why. Book a myo intake, link in bio.'
[0:54] End card."""),
        'schedule': ('1', 'Tue', '2026-04-15'),
        # LinkedIn posts Tue, TikTok posts Wed, YouTube Shorts posts Tue
        'li_date': '2026-04-15',
        'igtk_ig_date': '2026-04-15',
        'igtk_tk_date': '2026-04-16',
        'yt_date': '2026-04-15',
    },
    'short2': {
        'caption': 'The window is smaller than most parents realize.\n\n#myotherapy #parenting #kidshealth',
        'linkedin_script': strip_source("""[0:00] Camera straight on, clinical setting, Amanda seated at desk. No intro music. Cut straight to face.
[0:03] 'The most common thing I see when a parent walks into a myo intake appointment is this: they think we\'re going to work on their child\'s speech sounds.'
[0:10] 'They come in expecting articulation drills. They think myo therapy is speech therapy for pronunciation.'
[0:16] 'It\'s not.'
[0:18] 'Myo therapy addresses the muscle function patterns that affect dental alignment, airway health, and sleep quality. We are working on tongue posture. Oral rest posture. Swallowing mechanics. Nasal breathing habits.'
[0:33] 'At rest, the tongue should sit gently against the roof of the mouth. Lips are closed. Breathing happens through the nose. When those patterns are off, the pressure from every swallow, and a child swallows between 500 and 1,000 times a day, that pressure keeps working against the teeth.'
[0:50] 'The ortho referral is not a suggestion. It\'s a clinical observation from someone who has examined your child\'s oral structures closely.'
[1:05] 'If you have that referral and you\'re not sure what to do next, follow @lastinglanguage. The link in my bio takes you to our free resource library.'"""),
        'igtk_script': strip_source("""[0:00] Cut straight in. Close frame on Amanda.
[0:01] 'What actually happens in a myo intake appointment. Thirty seconds, no fluff.'
[0:05] 'First I ask the parent what the ortho said. Word for word. Because what the ortho said and what the parent heard are usually two different things.'
[0:12] 'Then I observe the child before I ask them anything. Where does the tongue sit at rest? Are the lips closed? Are they breathing through the nose or the mouth?'
[0:20] 'Then the clinical piece. Tongue posture. Oral rest posture. Lip seal. Swallowing mechanics. I have the child swallow and I watch for a tongue thrust pattern, meaning the tongue pushes forward instead of pressing up against the roof of the mouth.'
[0:32] 'That forward pressure doesn\'t stop because you put braces on. That\'s the whole reason the ortho referred.'
[0:38] 'The intake takes about an hour. You leave knowing exactly what your child needs. Follow for more.'"""),
        'ytshorts_script': strip_source("""[0:00] Amanda, casual and direct. No intro.
[0:02] 'Most common misconception parents have about myo therapy: they think it is for speech sounds. It is not.'
[0:10] 'Myofunctional therapy addresses tongue posture, lip seal, jaw development, breathing patterns, and the swallow. Those are the muscle functions that influence how teeth move and how the airway develops.'
[0:25] 'When your orthodontist refers your child for myo, they are not saying your child has a speech delay. They are saying there is a muscle pattern that will work against the orthodontic treatment.'
[0:38] 'The intake takes about an hour. We look at rest posture, we film the swallow, we map what we find to your child\'s orthodontic plan.'
[0:50] 'You leave knowing exactly what is happening and what comes next. Booking link in bio.'
[1:00] End."""),
        'schedule': ('1', 'Thu', '2026-04-17'),
        'li_date': '2026-04-17',
        'igtk_ig_date': '2026-04-17',
        'igtk_tk_date': '2026-04-18',
        'yt_date': '2026-04-17',
    },
    'short3': {
        'caption': 'Hospital neuro rehab taught me things private practice never would have.\n\n#myotherapy #clinicianlife',
        'linkedin_script': strip_source("""[0:00] Amanda at desk, facing camera directly. No greeting. Immediate.
[0:02] 'I want to say something that took me years in hospital SLP to be able to articulate clearly. The credential and the system are two different things. The hospital gave me the best clinical training available. The system structurally could not give patients what they needed. Both of those are true at the same time.'
[0:18] 'The case that clarified it for me was Parkinson\'s voice therapy. LSVT LOUD is a 16-session, four-week protocol at four sessions per week. That structure is not administrative convenience. The intensity is the intervention.'
[0:40] 'What does an outpatient insurance-based setting actually schedule for a Parkinson\'s patient? One session per week. Sometimes two. At 30 to 45 minutes. That is not LSVT LOUD. That is a different thing with the same name applied loosely. And families often have no way to know the difference.'
[0:58] 'I left because I wanted to actually run the protocol. That means a private practice model where session frequency is determined by what the evidence says patients need, not what the schedule can accommodate. That is the practice I built.'
[1:16] 'If you are a caregiver for a Parkinson\'s patient and you want to understand what the right speech intervention actually looks like, the link in the bio has more. Or reach out directly.'"""),
        'igtk_script': strip_source("""[0:00] Amanda, direct. No lead-in.
[0:02] 'LSVT LOUD is the gold-standard voice therapy for Parkinson\'s disease. Here is what it actually is and why most SLPs are not certified to run it.'
[0:10] 'Parkinson\'s creates a calibration error. The brain stops accurately perceiving how loud the patient is actually speaking. The patient thinks their voice is normal volume. Everyone around them can barely hear them. Generic voice therapy that tells the patient to speak louder does not recalibrate the system. LSVT LOUD does.'
[0:26] 'The protocol is 16 sessions over 4 weeks at four sessions per week. Each session is one hour. That frequency is not arbitrary. It is what the research showed is required to produce the neurological reorganization. You cannot run it correctly at one session per week.'
[0:40] 'Most SLPs are not LSVT LOUD certified because the training requires completing a specific formal program. General voice therapy knowledge is not the same thing. When you are choosing an SLP for Parkinson\'s, ask if they are certified. That one question changes the conversation. Link in bio.'"""),
        'ytshorts_script': strip_source("""[0:00] Amanda, direct to camera, relaxed but clear.
[0:02] 'I spent years in hospital acute care doing SLP work with stroke survivors, Parkinson\'s patients, TBI cases.'
[0:10] 'When I went into private practice, the clinical training was the same. What changed was how much time I had per patient, how often I could see them, and how closely I could follow the protocols that actually work.'
[0:26] 'In hospital, you get 30 to 45 minutes, once or twice a week, in a shared space. In private practice, sessions are longer. Scheduling is built around the protocol, not the other way around.'
[0:40] 'Same SLP training. Different system. Different outcomes.'
[0:48] 'If you are a Parkinson\'s patient looking for LSVT LOUD in the Atlanta area, the booking link is in my bio.'
[0:58] End."""),
        'schedule': ('2', 'Tue', '2026-04-22'),
        'li_date': '2026-04-22',
        'igtk_ig_date': '2026-04-22',
        'igtk_tk_date': '2026-04-23',
        'yt_date': '2026-04-22',
    },
    'short4': {
        'caption': 'One step at a time. No reason to wait.\n\n#myotherapy #parenting',
        'linkedin_script': strip_source("""[0:00] Amanda at desk or standing beside a printed anatomy diagram. Direct to camera.
[0:02] 'Between ages 6 and 12, the jaw and palate are still actively developing. That is not a generalization. That is a clinical fact with direct implications for myofunctional therapy outcomes.'
[0:15] 'During this window, the palate is still malleable. Muscle function patterns, including tongue posture, swallowing mechanics, and oral rest posture, directly influence the shape of the dental arch and the development of the airway.'
[0:27] 'When we address a tongue thrust or low tongue posture during this window, we\'re not just correcting a habit. We\'re supporting structural development that\'s happening in real time.'
[0:38] 'For children outside this window, myo therapy is still effective. I want to be clear about that. Adults complete myo therapy successfully. But the structural malleability that makes ages 6 to 12 significant is no longer a factor.'
[0:52] 'So if your child\'s orthodontist referred for myo therapy and your child is in that 6 to 12 range, that is the most relevant clinical reason to act now.'
[1:02] 'The intake consult is free. No charge. No obligation. You come in, we evaluate tongue posture, swallowing mechanics, lip seal, and nasal breathing patterns. You leave knowing exactly where your child stands.'
[1:15] 'Link in my bio. Lasting Language Therapy, Sandy Springs, Georgia. Follow for more on myofunctional therapy and pediatric oral health.'"""),
        'igtk_script': strip_source("""[0:00] Straight cut, close frame, Amanda speaking directly.
[0:01] 'Why did your orthodontist refer your child for myo therapy? Here\'s the mechanism in thirty seconds.'
[0:06] 'Braces move teeth into alignment. But swallowing patterns keep applying pressure afterward.'
[0:12] 'A tongue thrust swallowing pattern means the tongue pushes forward against the front teeth with every swallow. A child swallows somewhere between 500 and 1,000 times per day.'
[0:22] 'That forward pressure works against orthodontic treatment. It can push teeth back out of alignment after braces come off.'
[0:28] 'Myo therapy addresses the swallowing mechanics, tongue posture, and oral rest posture that make orthodontic results last.'
[0:35] 'Free intake consult if you have an ortho referral. Link in bio.'"""),
        'ytshorts_script': strip_source("""[0:00] Amanda, direct to camera. Informational but accessible.
[0:02] 'Between ages 6 and 12, the jaw and palate are still actively developing. That developmental window is why early myo therapy has a different outcome than the same therapy in a teenager or adult.'
[0:16] 'At this age, we are not just correcting a habit. We are working with tissue that is still plastic. The palate can widen. The jaw can be shaped by the forces acting on it. The airway responds.'
[0:30] 'When your orthodontist refers a child in this age range for myo therapy, the timing is intentional. They are trying to use that developmental window before it closes.'
[0:43] 'A myo intake at age seven or eight can change the trajectory of orthodontic treatment entirely. Sometimes significantly.'
[0:55] 'Intake booking link is in my bio. If your child is in this age range and has been referred, do not wait.'
[1:03] End."""),
        'schedule': ('2', 'Thu', '2026-04-24'),
        'li_date': '2026-04-24',
        'igtk_ig_date': '2026-04-24',
        'igtk_tk_date': '2026-04-25',
        'yt_date': '2026-04-24',
    },
}

BUNDLE_TITLES = {
    'short1': {
        'li':   'Braces Move Teeth — Swallowing Patterns Are What Makes Them Stay',
        'igtk': 'What the Free Intake Consult Actually Looks Like',
        'yt':   '3 Reasons Orthodontic Patients Relapse Without Myo',
    },
    'short2': {
        'li':   'Myo Therapy Is Not Speech Therapy for Pronunciation',
        'igtk': 'What Actually Happens in a Myo Intake — 30 Seconds',
        'yt':   'The Most Common Misconception About Myo Therapy',
    },
    'short3': {
        'li':   'The Credential and the System Are Two Different Things',
        'igtk': 'LSVT LOUD — What It Is and Why Most SLPs Aren\'t Certified',
        'yt':   'Same SLP Training, Different System, Different Outcomes',
    },
    'short4': {
        'li':   'Ages 6–12 Is the Window When Myo Therapy Changes the Structure',
        'igtk': 'Why Your Orthodontist Referred for Myo — The Mechanism in 30 Seconds',
        'yt':   'Why Early Myo Therapy Has a Different Outcome',
    },
}

def build_short_rows():
    # Columns: piece_id, Title, Type, Platforms, Week, Day, Date, Script, Caption, Status, Notes, Images, Platform Schedule
    rows = []
    for bid, data in BUNDLE_DATA.items():
        week, day, date = data['schedule']
        caption = data['caption']
        titles = BUNDLE_TITLES[bid]

        # LinkedIn row
        rows.append([
            f'{bid}-li', titles['li'], 'Short-Form Video', 'LinkedIn',
            week, day, data['li_date'], data['linkedin_script'], caption, 'Draft', '', '', ''
        ])

        # IG + TikTok row with Platform Schedule for different days
        ig_date = data['igtk_ig_date']
        tk_date = data['igtk_tk_date']
        # Primary date = IG date (first to post)
        platform_schedule = f'Instagram Reels: {ig_date} | TikTok: {tk_date}'
        rows.append([
            f'{bid}-igtk', titles['igtk'], 'Short-Form Video', 'Instagram Reels, TikTok',
            week, day, ig_date, data['igtk_script'], caption, 'Draft', '', '', platform_schedule
        ])

        # YouTube Shorts row
        rows.append([
            f'{bid}-yt', titles['yt'], 'Short-Form Video', 'YouTube Shorts',
            week, day, data['yt_date'], data['ytshorts_script'], caption, 'Draft', '', '', ''
        ])
    return rows

def main():
    # Load non-short rows from existing sheet data
    existing = json.loads(Path("/Users/bryce/FLSM/.tmp/content_rows.json").read_text())
    all_rows = existing["values"]
    header_old = all_rows[0]  # old 12-col header

    # Build new 13-col header with Platform Schedule
    header = ['piece_id', 'Title', 'Type', 'Platforms', 'Week', 'Day', 'Date',
              'Script', 'Caption', 'Status', 'Notes', 'Images', 'Platform Schedule']

    # Non-short rows from old data (13 rows): add empty Platform Schedule column
    non_short = [r + [''] for r in all_rows[1:] if not r[0].startswith('short')]

    # Build new short rows (12 instead of 20)
    short_rows = build_short_rows()

    print(f"Non-short rows: {len(non_short)}")
    print(f"Short rows: {len(short_rows)}")

    DAYS_ORDER = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    TYPE_ORDER = {'YouTube Long-Form': 0, 'Short-Form Video': 1, 'LinkedIn Carousel': 2, 'IG/TT Carousel': 3, 'Blog Post': 4, 'Email': 5}

    all_data = non_short + short_rows
    def sort_key(r):
        week = int(r[4]) if str(r[4]).isdigit() else 99
        day_idx = DAYS_ORDER.index(r[5]) if r[5] in DAYS_ORDER else 99
        type_idx = TYPE_ORDER.get(r[2], 10)
        return (week, day_idx, type_idx, r[0])

    all_data.sort(key=sort_key)

    final_values = [header] + all_data
    print(f"Total rows (with header): {len(final_values)}")
    for r in all_data:
        ps = r[12] if len(r) > 12 and r[12] else ''
        print(f"  {r[0]:14s} | {r[1][:45]:45s} | {r[3]:25s} | {ps[:30] if ps else ''}")

    # Clear then write
    sheets_request("POST", f"{SHEET_ID}/values/Content!A1:M100:clear")
    encoded = urllib.parse.quote("Content!A1")
    result = sheets_request("PUT", f"{SHEET_ID}/values/{encoded}?valueInputOption=RAW", {
        "range": "Content!A1", "majorDimension": "ROWS", "values": final_values
    })
    print(f"\nSuccess: {result.get('updatedRows',0)} rows, {result.get('updatedCells',0)} cells")
    print(f"Range: {result.get('updatedRange','')}")

if __name__ == "__main__":
    main()
