#!/usr/bin/env python3
"""Group Text Manager — shared SMS threads with external parties.

Thin shell: auth, chrome and styling only. All behaviour lives in
group_text.js talking to textbridge_api via /api/textbridge/, which is
cookie-authenticated against the same `group_text` page key enforced here.
"""

import cgi
import sys

sys.path.insert(0, '/opt/ngon/apps')
sys.path.insert(0, '/var/www/html/ngon')
from managers.auth_manager import AuthManager, generate_login_page_html
from links import generate_dropdown_html, generate_dropdown_css, generate_dropdown_js

form = cgi.FieldStorage()
auth = AuthManager('group_text')
auth_required, should_exit, headers = auth.require_auth(form)

if should_exit:
    print("Content-Type: application/json")
    if headers:
        print(headers)
    print("")
    if auth_required:
        print('{"success": false, "error": "Authentication required"}')
    else:
        print('{"success": true}')
    sys.exit(0)

if auth_required:
    print("Content-Type: text/html\n")
    print(generate_login_page_html("Group Text Manager"))
    sys.exit(0)

access = AuthManager.get_user_access()

print("Content-Type: text/html\n")
print(f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Group Text Manager</title>
<style>
/* generate_dropdown_css() returns BARE CSS with no <style> tags, exactly like
   generate_dropdown_js() returns bare JS. Outside a style block it applies
   nothing -- .dropdown-content never gets display:none, so all 32 nav links
   render as visible text -- and the stylesheet itself prints on the page.
   It goes first so the .header rules below win on source order. */
{generate_dropdown_css()}

    * {{ box-sizing: border-box; }}
    /* House scrollbar: 6px, #666 thumb on a transparent track, #888 on hover.
       Matches bridge_status.py, how_to_site_issues.py and the status modals.
       Applied with the * selector so every scrolling pane on the page picks it
       up -- thread list, message pane, members panel, directory modal. */
    ::-webkit-scrollbar {{ width: 6px; height: 6px; }}
    ::-webkit-scrollbar-track {{ background: transparent; }}
    ::-webkit-scrollbar-thumb {{ background: #666; border-radius: 3px; }}
    ::-webkit-scrollbar-thumb:hover {{ background: #888; }}
    ::-webkit-scrollbar-corner {{ background: transparent; }}
    /* Firefox has no ::-webkit pseudo-elements */
    * {{ scrollbar-width: thin; scrollbar-color: #666 transparent; }}
    body {{
        margin: 0; background: #111; color: #e0e0e0;
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    }}
    /* generate_dropdown_css ships its own .header that would otherwise win */
    .header {{
        background-color: rgba(255,255,255,0.05) !important;
        border-radius: 8px !important;
        padding: 20px 30px !important;
        margin: 20px !important;
        border: 1px solid rgba(255,255,255,0.1) !important;
        display: flex !important;
        justify-content: space-between !important;
        align-items: center !important;
        flex-wrap: wrap !important;
        gap: 12px !important;
    }}
    /* Deliberately no font-size here -- it would out-specify .dropdown-title
       from generate_dropdown_css() and silently shrink the heading. */
    .header h1 {{ margin: 0; }}

    .dev-strip {{
        margin: 0 20px 12px; display: flex; gap: 8px;
        align-items: center; flex-wrap: wrap; font-size: 12px;
    }}
    .dev-chip {{
        padding: 5px 10px; border-radius: 12px; border: 1px solid;
        display: inline-flex; gap: 6px; align-items: center;
    }}
    .dev-chip.good {{ color: #00ff00; border-color: rgba(0,255,0,.35); background: rgba(0,255,0,.07); }}
    .dev-chip.warn {{ color: #ffaa00; border-color: rgba(255,170,0,.35); background: rgba(255,170,0,.07); }}
    .dev-chip.bad  {{ color: #ff4444; border-color: rgba(255,68,68,.35); background: rgba(255,68,68,.07); }}
    .dev-bits {{ color: #888; font-weight: 400; }}

    .layout {{
        display: grid; grid-template-columns: 280px 1fr;
        gap: 16px; margin: 0 20px 20px; height: calc(100vh - 210px);
    }}
    .panel {{
        background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.1);
        border-radius: 8px; overflow: hidden; display: flex; flex-direction: column;
    }}
    .panel-head {{
        padding: 12px 16px; border-bottom: 1px solid rgba(255,255,255,.1);
        display: flex; justify-content: space-between; align-items: center; gap: 8px;
    }}
    .panel-head h2 {{ margin: 0; font-size: 14px; font-weight: 600; }}
    .panel-head .meta {{ color: #888; font-size: 11px; margin-top: 3px; }}

    #groupList {{ overflow-y: auto; flex: 1; }}
    .site-label {{
        padding: 10px 16px 4px; color: #666; font-size: 10px;
        text-transform: uppercase; letter-spacing: .08em;
    }}
    .thread {{ padding: 9px 16px; cursor: pointer; border-left: 2px solid transparent; }}
    .thread:hover {{ background: rgba(255,255,255,.04); }}
    .thread.active {{ background: rgba(74,158,255,.12); border-left-color: #4a9eff; }}
    .thread.archived {{ opacity: .5; }}
    .thread.archived .thread-name::after {{
        content: ' (archived)'; color: #777; font-size: 10px;
    }}
    .thread-top {{ display: flex; justify-content: space-between; align-items: center; }}
    .thread-name {{ font-size: 13px; }}
    .thread-sub {{ color: #777; font-size: 11px; margin-top: 2px; }}
    .unread {{ width: 8px; height: 8px; border-radius: 50%; background: #4a9eff; }}
    .unread.amber {{ background: #ffaa00; }}
    .thread.unassigned {{ border-left-color: #ffaa00; }}
    .unassigned-thread {{
        border: 1px solid rgba(255,170,0,.3); background: rgba(255,170,0,.06);
        border-radius: 8px; padding: 12px; margin-bottom: 16px;
    }}
    .ut-head {{
        display: flex; justify-content: space-between; align-items: flex-start;
        gap: 12px; margin-bottom: 10px; padding-bottom: 10px;
        border-bottom: 1px solid rgba(255,170,0,.2);
    }}
    .ut-nums {{ color: #999; font-size: 11px; margin-top: 3px; }}
    .ut-assign {{
        background-color: #2a2a2a; color: #e0e0e0; font-size: 11px;
        border: 1px solid rgba(255,255,255,.15); border-radius: 6px; padding: 5px 8px;
    }}
    .ut-assign option {{ background-color: #2a2a2a; color: #e0e0e0; }}
    .ut-hint {{
        margin-top: 6px; font-size: 11px; color: #ffcc66;
        background: rgba(255,170,0,.1); border-radius: 5px;
        padding: 5px 8px; line-height: 1.5;
    }}

    #messages {{ flex: 1; overflow-y: auto; padding: 16px; }}
    .msg {{ margin-bottom: 14px; max-width: 72%; width: fit-content; }}
    .msg.out {{ margin-left: auto; }}
    .msg-head {{ display: flex; gap: 8px; align-items: center; font-size: 11px; margin-bottom: 3px; }}
    .msg.out .msg-head {{ justify-content: flex-end; }}
    .msg-who {{ color: #4a9eff; font-weight: 600; }}
    .msg.in .msg-who {{ color: #00ff00; }}
    .msg-time {{ color: #666; }}
    .msg-body {{
        background: rgba(255,255,255,.06); padding: 9px 12px;
        border-radius: 10px; font-size: 13px; line-height: 1.45;
        white-space: normal; word-wrap: break-word;
    }}
    .msg.out .msg-body {{ background: rgba(74,158,255,.15); }}
    .msg-img {{ max-width: 260px; border-radius: 8px; margin-top: 8px; display: block; }}
    /* A picture-only MMS has no text to wrap, so drop the bubble entirely and
       let the image be its own shape. */
    .msg-body.media-only {{ background: none; padding: 0; }}
    .msg-body.media-only .msg-img {{ margin-top: 0; }}
    .msg.out .msg-body.media-only {{ background: none; }}
    .msg-file {{ display: inline-block; margin-top: 8px; color: #4a9eff; font-size: 12px; }}
    .msg-status {{ font-size: 10px; padding: 1px 6px; border-radius: 8px; }}
    .msg-status.ok {{ color: #00ff00; background: rgba(0,255,0,.1); }}
    .msg-status.q {{ color: #888; background: rgba(255,255,255,.07); }}
    .msg-status.warn {{ color: #ffaa00; background: rgba(255,170,0,.1); }}
    .msg-status.bad {{ color: #ff4444; background: rgba(255,68,68,.1); }}

    #composer {{
        display: none; padding: 12px; gap: 8px;
        border-top: 1px solid rgba(255,255,255,.1);
    }}
    #input {{
        flex: 1; background: rgba(255,255,255,.06); color: #e0e0e0;
        border: 1px solid rgba(255,255,255,.12); border-radius: 6px;
        padding: 9px 12px; font-size: 13px; resize: none; height: 40px;
        font-family: inherit;
    }}
    button {{
        background: rgba(74,158,255,.15); color: #4a9eff; cursor: pointer;
        border: 1px solid rgba(74,158,255,.35); border-radius: 6px;
        padding: 8px 14px; font-size: 12px; font-family: inherit;
    }}
    button:hover {{ background: rgba(74,158,255,.25); }}
    button:disabled {{ opacity: .5; cursor: default; }}
    button.mini {{ padding: 4px 9px; font-size: 11px; }}
    button.danger {{ color: #ff4444; border-color: rgba(255,68,68,.35); background: rgba(255,68,68,.1); }}

    #membersPanel {{
        border-top: 1px solid rgba(255,255,255,.1);
        max-height: 0; overflow: hidden; transition: max-height .2s;
    }}
    #membersPanel.open {{ max-height: 340px; overflow-y: auto; }}
    .member {{
        display: flex; justify-content: space-between; align-items: center;
        padding: 8px 16px; border-bottom: 1px solid rgba(255,255,255,.05);
    }}
    .member-name {{ font-size: 13px; }}
    .member-num {{ color: #777; font-size: 11px; }}
    .add-member {{ display: flex; gap: 8px; padding: 10px 16px; flex-wrap: wrap; }}
    .add-member input {{
        background: rgba(255,255,255,.06); color: #e0e0e0; font-size: 12px;
        border: 1px solid rgba(255,255,255,.12); border-radius: 6px; padding: 7px 10px;
    }}

    .empty {{ color: #666; text-align: center; padding: 40px 20px; font-size: 13px; line-height: 1.6; }}
    .empty.small {{ padding: 16px; font-size: 12px; }}
    .muted {{ color: #666; }}

    .modal {{
        display: none; position: fixed; inset: 0; background: rgba(0,0,0,.7);
        align-items: center; justify-content: center; z-index: 1000;
    }}
    .modal-box {{
        background: #1a1a1a; border: 1px solid rgba(255,255,255,.15);
        border-radius: 10px; padding: 24px; width: 420px; max-width: 92vw;
    }}
    .modal-box.wide {{ width: 720px; max-height: 85vh; overflow-y: auto; }}
    .modal-box h3 {{ margin: 0 0 16px; font-size: 16px; }}
    .dir-add {{
        display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 14px;
        padding-bottom: 14px; border-bottom: 1px solid rgba(255,255,255,.1);
    }}
    .dir-add input {{
        background: rgba(255,255,255,.06); color: #e0e0e0; font-size: 12px;
        border: 1px solid rgba(255,255,255,.12); border-radius: 6px; padding: 7px 10px;
    }}
    .dir-row {{
        padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,.06);
        display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
    }}
    .dir-who {{ font-size: 13px; display: flex; align-items: center; gap: 8px; }}
    .dir-edit {{
        background: transparent; border: 1px solid transparent; color: #e0e0e0;
        border-radius: 4px; padding: 2px 5px; font-family: inherit; font-size: 11px;
    }}
    .dir-edit.name {{ font-size: 13px; }}
    .dir-edit:hover {{ border-color: rgba(255,255,255,.15); }}
    .dir-edit:focus {{
        border-color: #4a9eff; background: rgba(255,255,255,.06); outline: none;
    }}
    .dir-edit::placeholder {{ color: #666; font-style: italic; }}
    .dir-sub {{ color: #777; font-size: 11px; margin-top: 3px; }}
    .dir-groups {{ display: flex; gap: 5px; flex-wrap: wrap; margin-top: 6px; }}
    .grp-tag {{
        font-size: 10px; padding: 2px 7px; border-radius: 10px;
        background: rgba(74,158,255,.15); color: #4a9eff; cursor: pointer;
    }}
    .grp-tag.off {{ background: rgba(255,255,255,.06); color: #777; }}
    .chat-tag {{
        font-size: 10px; padding: 2px 7px; border-radius: 10px;
        background: rgba(0,255,0,.12); color: #00ff00;
    }}
    .unmapped {{
        background: rgba(255,170,0,.08); border: 1px solid rgba(255,170,0,.3);
        border-radius: 6px; padding: 12px; margin-bottom: 14px; font-size: 12px;
    }}
    .unmapped h4 {{ margin: 0 0 6px; font-size: 12px; color: #ffaa00; }}
    .unmapped .hint {{ color: #999; margin-bottom: 10px; line-height: 1.5; }}
    .unmapped-row {{ display: flex; gap: 8px; align-items: center; margin-top: 6px; }}
    .unmapped-row select {{
        background-color: #2a2a2a; color: #e0e0e0; font-size: 12px;
        border: 1px solid rgba(255,255,255,.12); border-radius: 6px; padding: 5px 8px;
    }}
    .field {{ margin-bottom: 12px; }}
    .field label {{ display: block; color: #888; font-size: 11px; margin-bottom: 4px; }}
    .field input[type=text], .field select {{
        width: 100%; background: rgba(255,255,255,.06); color: #e0e0e0;
        border: 1px solid rgba(255,255,255,.12); border-radius: 6px;
        padding: 8px 10px; font-size: 13px; font-family: inherit;
    }}
    /* <option> does not inherit the <select>'s background, and a translucent
       rgba() leaves the native popup rendering white -- light text on white.
       Both need an explicit solid colour. */
    .field select {{ background-color: #2a2a2a; }}
    .field select option {{ background-color: #2a2a2a; color: #e0e0e0; }}
    .field .hint {{ color: #666; font-size: 11px; margin-top: 4px; line-height: 1.4; }}
    .modal-actions {{ display: flex; justify-content: flex-end; gap: 8px; margin-top: 18px; }}

    .toast {{
        position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%);
        background: #222; border: 1px solid rgba(255,255,255,.2); color: #e0e0e0;
        padding: 11px 18px; border-radius: 8px; font-size: 13px;
        opacity: 0; pointer-events: none; transition: opacity .2s; max-width: 80vw;
    }}
    .toast.show {{ opacity: 1; }}
    .toast.error {{ border-color: rgba(255,68,68,.5); color: #ff8888; }}

    @media (max-width: 780px) {{
        .layout {{ grid-template-columns: 1fr; height: auto; }}
        #groupList {{ max-height: 220px; }}
        #messages {{ height: 55vh; }}
        .msg {{ max-width: 90%; }}
    }}
</style>
</head>
<body>

<div class="header">
    <div class="dropdown">
        <h1 class="dropdown-title">Group Text Manager</h1>
        <div class="dropdown-content">
            {generate_dropdown_html(access)}
        </div>
    </div>
    <div style="display:flex; gap:8px; align-items:center;">
        <button id="directoryBtn">Directory</button>
        <button id="newGroupBtn">New group</button>
        <button id="editGroupBtn">Edit group</button>
    </div>
</div>

<div class="dev-strip" id="deviceStrip"></div>

<div class="layout">
    <div class="panel">
        <div class="panel-head">
            <h2>Threads</h2>
            <button class="mini" id="showArchivedBtn">Show archived</button>
        </div>
        <div id="groupList"></div>
    </div>

    <div class="panel">
        <div class="panel-head">
            <div>
                <h2 id="threadTitle">Select a thread</h2>
                <div class="meta" id="threadMeta"></div>
            </div>
            <button class="mini" id="membersToggle">Members (<span id="memberCount">0</span>)</button>
        </div>
        <div id="membersPanel">
            <div id="memberList"></div>
            <div class="add-member">
                <input type="text" id="newNumber" placeholder="817-650-8051 (any format)" size="20">
                <input type="text" id="newName" placeholder="Name (optional)" size="14">
                <button class="mini" id="addMemberBtn">Add</button>
            </div>
        </div>
        <div id="messages"><div class="empty">Pick a thread on the left.</div></div>
        <div id="composer">
            <textarea id="input" placeholder="Message… (Enter to send, Shift+Enter for a new line)"></textarea>
            <button id="sendBtn">Send</button>
        </div>
    </div>
</div>

<div class="modal" id="dirModal">
    <div class="modal-box wide">
        <h3>Directory
            <button class="mini" id="dirSyncBtn" style="float:right;font-weight:400;"
                    title="Pull NGON staff from Google so their Chat messages show their name">
                Sync from Google</button>
        </h3>
        <div id="unmappedBox"></div>
        <div class="dir-add">
            <input type="text" id="dName" placeholder="Name" size="14">
            <input type="text" id="dPhone" placeholder="Phone (any format)" size="16">
            <input type="text" id="dCompany" placeholder="Company" size="12">
            <input type="text" id="dRole" placeholder="Role" size="10">
            <button class="mini" id="dAddBtn">Add person</button>
        </div>
        <div id="dirList"></div>
        <div class="modal-actions">
            <button id="dirCloseBtn">Close</button>
        </div>
    </div>
</div>

<div class="modal" id="groupModal">
    <div class="modal-box">
        <h3 id="modalTitle">New group</h3>
        <div class="field">
            <label>Name</label>
            <input type="text" id="gName" placeholder="Ellyson — Gas Provider (Acme)">
        </div>
        <div class="field">
            <label>Site</label>
            <input type="text" id="gSite" placeholder="Ellyson">
            <div class="hint">Groups the thread list. Leave blank for fleet-wide threads.</div>
        </div>
        <div class="field">
            <label>Counterparty type</label>
            <input type="text" id="gType" placeholder="gas_provider / gas_processor / gen_service">
        </div>
        <div class="field">
            <label>Owner</label>
            <input type="text" id="gOwner" placeholder="Who at NGON runs this thread">
        </div>
        <div class="field">
            <label>Google Chat Space</label>
            <select id="gSpace"><option value="">— not bridged —</option></select>
            <div class="hint">
                The internal side of this thread. Anything posted in that Space
                is sent as a text to everyone in this group, so only map a Space
                created for this purpose — never an internal site chat.
            </div>
        </div>
        <div class="field">
            <label>Mode</label>
            <select id="gMode">
                <option value="broadcast">Broadcast — individual SMS to each member</option>
                <option value="mms_group">Group MMS — one shared thread</option>
            </select>
            <div class="hint">
                Broadcast is what works today: everyone gets a normal text and replies
                come back here, but members don't see each other's replies. Group MMS
                needs an app that can send it — ours can't yet.
            </div>
        </div>
        <div class="field">
            <label style="display:flex; gap:8px; align-items:center;">
                <input type="checkbox" id="gSystem" style="width:auto;">
                Allow automated/system posts
            </label>
            <div class="hint">
                Off by default. Automated alerts texted to a third party are the
                fastest way to get a thread muted.
            </div>
        </div>
        <div class="modal-actions">
            <button class="danger" id="archiveGroupBtn"
                    style="margin-right:auto;">Archive group</button>
            <button id="cancelGroupBtn">Cancel</button>
            <button id="saveGroupBtn">Save</button>
        </div>
    </div>
</div>

<div class="toast" id="toast"></div>

<script>
{generate_dropdown_js()}
</script>
<script src="/status/group_text.js"></script>
</body>
</html>""")
