/**
 * Test script — simulates a CC agent (Rekha) receiving a call and using the AI assistant.
 * Tests: auth → lead lookup → patient data → doctor data → appointments → calls → activities → AI response
 *
 * Run: cd helix-engage && npx tsx scripts/test-ai-flow.ts
 */

const GQL = process.env.SEED_GQL ?? 'http://localhost:4000/graphql';
const SUB = 'fortytwo-dev';
const ORIGIN = process.env.SEED_ORIGIN ?? 'http://fortytwo-dev.localhost:4010';

// Rekha's credentials
const AGENT_EMAIL = 'rekha.cc@globalhospital.com';
const AGENT_PASSWORD = 'Global@123';

// Simulated incoming call — Priya's phone
const CALLER_PHONE = '9949879837';

let token = '';
let failures = 0;

async function gql(query: string, variables?: any) {
    const h: Record<string, string> = { 'Content-Type': 'application/json', 'X-Workspace-Subdomain': SUB };
    if (token) h['Authorization'] = `Bearer ${token}`;
    const r = await fetch(GQL, { method: 'POST', headers: h, body: JSON.stringify({ query, variables }) });
    const d: any = await r.json();
    if (d.errors) throw new Error(d.errors[0].message);
    return d.data;
}

function assert(condition: boolean, label: string, detail?: string) {
    if (condition) {
        console.log(`  ✅ ${label}${detail ? ` — ${detail}` : ''}`);
    } else {
        console.log(`  ❌ ${label}${detail ? ` — ${detail}` : ''}`);
        failures++;
    }
}

async function main() {
    console.log('🧪 Helix Engage — AI Flow Test\n');
    console.log(`Agent: ${AGENT_EMAIL}`);
    console.log(`Incoming call from: ${CALLER_PHONE}\n`);

    // ═══════════════════════════════════════
    // STEP 1: Login as Rekha
    // ═══════════════════════════════════════
    console.log('1️⃣  LOGIN');
    const d1 = await gql(`mutation { getLoginTokenFromCredentials(email: "${AGENT_EMAIL}", password: "${AGENT_PASSWORD}", origin: "${ORIGIN}") { loginToken { token } } }`);
    const lt = d1.getLoginTokenFromCredentials.loginToken.token;
    const d2 = await gql(`mutation { getAuthTokensFromLoginToken(loginToken: "${lt}", origin: "${ORIGIN}") { tokens { accessOrWorkspaceAgnosticToken { token } } } }`);
    token = d2.getAuthTokensFromLoginToken.tokens.accessOrWorkspaceAgnosticToken.token;
    assert(!!token, 'Authenticated as Rekha');

    // Verify role
    const profile = await gql('{ currentUser { email workspaceMember { name { firstName lastName } roles { label } } } }');
    const roles = profile.currentUser.workspaceMember.roles.map((r: any) => r.label);
    const name = `${profile.currentUser.workspaceMember.name.firstName} ${profile.currentUser.workspaceMember.name.lastName}`;
    assert(roles.includes('HelixEngage User'), `Role: ${roles.join(', ')}`);
    assert(name.includes('Rekha'), `Name: ${name}`);

    // ═══════════════════════════════════════
    // STEP 2: Look up caller by phone number
    // ═══════════════════════════════════════
    console.log('\n2️⃣  LEAD LOOKUP (by phone: 9949879837)');
    const leadsData = await gql(`{ leads(first: 50) { edges { node {
        id name contactName { firstName lastName }
        contactPhone { primaryPhoneNumber }
        contactEmail { primaryEmail }
        source status interestedService assignedAgent
        leadScore contactAttempts firstContacted lastContacted
        aiSummary aiSuggestedAction
        patientId campaignId
    } } } }`);

    const leads = leadsData.leads.edges.map((e: any) => e.node);
    assert(leads.length > 0, `Found ${leads.length} leads total`);

    // Match by phone
    const matchedLead = leads.find((l: any) => {
        const phone = l.contactPhone?.primaryPhoneNumber ?? '';
        return phone.includes(CALLER_PHONE) || CALLER_PHONE.includes(phone);
    });

    assert(!!matchedLead, 'Matched lead by phone', matchedLead?.name);
    assert(matchedLead?.contactName?.firstName === 'Priya', `First name: ${matchedLead?.contactName?.firstName}`);
    assert(matchedLead?.status === 'APPOINTMENT_SET', `Status: ${matchedLead?.status}`);
    assert(!!matchedLead?.aiSummary, 'Has AI summary', matchedLead?.aiSummary?.substring(0, 80) + '...');
    assert(!!matchedLead?.aiSuggestedAction, 'Has AI suggested action', matchedLead?.aiSuggestedAction);
    assert(!!matchedLead?.patientId, 'Linked to patient', matchedLead?.patientId);
    assert(!!matchedLead?.campaignId, 'Linked to campaign', matchedLead?.campaignId);

    const leadId = matchedLead?.id;
    const patientId = matchedLead?.patientId;

    // ═══════════════════════════════════════
    // STEP 3: Fetch patient record
    // ═══════════════════════════════════════
    console.log('\n3️⃣  PATIENT RECORD');
    if (patientId) {
        const patientData = await gql(`{ patients(first: 1, filter: { id: { eq: "${patientId}" } }) { edges { node {
            id name fullName { firstName lastName }
            phones { primaryPhoneNumber }
            emails { primaryEmail }
            dateOfBirth gender patientType
        } } } }`);
        const patient = patientData.patients.edges[0]?.node;
        assert(!!patient, 'Patient record found', patient?.name);
        assert(patient?.gender === 'FEMALE', `Gender: ${patient?.gender}`);
        assert(patient?.patientType === 'RETURNING', `Type: ${patient?.patientType}`);
        assert(!!patient?.dateOfBirth, `DOB: ${patient?.dateOfBirth}`);
    } else {
        assert(false, 'No patient ID to look up');
    }

    // ═══════════════════════════════════════
    // STEP 4: Fetch appointments for this patient
    // ═══════════════════════════════════════
    console.log('\n4️⃣  APPOINTMENTS');
    if (patientId) {
        const apptData = await gql(`{ appointments(first: 20, filter: { patientId: { eq: "${patientId}" } }) { edges { node {
            id name scheduledAt durationMin appointmentType status
            doctorName department reasonForVisit
            doctorId
        } } } }`);
        const appts = apptData.appointments.edges.map((e: any) => e.node);
        assert(appts.length >= 2, `Found ${appts.length} appointments`);

        const completed = appts.filter((a: any) => a.status === 'COMPLETED');
        const scheduled = appts.filter((a: any) => a.status === 'SCHEDULED');
        assert(completed.length >= 1, `${completed.length} completed`);
        assert(scheduled.length >= 1, `${scheduled.length} upcoming`);

        for (const a of appts) {
            const status = a.status === 'COMPLETED' ? '✓' : '📅';
            assert(!!a.doctorId, `${status} ${a.name} — doctor linked`, a.doctorId);
        }
    }

    // ═══════════════════════════════════════
    // STEP 5: Fetch doctor record (Dr. Patel)
    // ═══════════════════════════════════════
    console.log('\n5️⃣  DOCTOR LOOKUP');
    const doctorsData = await gql(`{ doctors(first: 10) { edges { node {
        id name fullName { firstName lastName }
        department specialty qualifications yearsOfExperience
        visitingHours
        consultationFeeNew { amountMicros currencyCode }
        consultationFeeFollowUp { amountMicros currencyCode }
        active registrationNumber
        portalUserId
        clinic { id clinicName }
    } } } }`);
    const doctors = doctorsData.doctors.edges.map((e: any) => e.node);
    assert(doctors.length === 5, `Found ${doctors.length} doctors`);

    const drPatel = doctors.find((d: any) => d.name?.includes('Patel'));
    assert(!!drPatel, 'Found Dr. Patel', drPatel?.specialty);
    assert(!!drPatel?.visitingHours, `Hours: ${drPatel?.visitingHours}`);
    assert(!!drPatel?.consultationFeeNew, `Fee (new): ₹${(drPatel?.consultationFeeNew?.amountMicros ?? 0) / 1_000_000}`);
    assert(!!drPatel?.portalUserId, 'Linked to workspace member', drPatel?.portalUserId);

    const drSharma = doctors.find((d: any) => d.name?.includes('Sharma'));
    assert(!!drSharma, 'Found Dr. Sharma', drSharma?.specialty);

    // ═══════════════════════════════════════
    // STEP 6: Fetch call history for this lead
    // ═══════════════════════════════════════
    console.log('\n6️⃣  CALL HISTORY');
    if (leadId) {
        const callsData = await gql(`{ calls(first: 20, filter: { leadId: { eq: "${leadId}" } }) { edges { node {
            id name direction callStatus agentName
            startedAt durationSec disposition
        } } } }`);
        const calls = callsData.calls.edges.map((e: any) => e.node);
        assert(calls.length >= 3, `Found ${calls.length} calls for Priya`);

        for (const c of calls) {
            console.log(`     ${c.direction} | ${c.disposition ?? c.callStatus} | ${c.name}`);
        }
    }

    // ═══════════════════════════════════════
    // STEP 7: Fetch lead activities
    // ═══════════════════════════════════════
    console.log('\n7️⃣  LEAD ACTIVITIES');
    if (leadId) {
        const activitiesData = await gql(`{ leadActivities(first: 30, filter: { leadId: { eq: "${leadId}" } }, orderBy: [{ occurredAt: DescNullsLast }]) { edges { node {
            id activityType summary occurredAt performedBy channel
        } } } }`);
        const activities = activitiesData.leadActivities.edges.map((e: any) => e.node);
        assert(activities.length >= 8, `Found ${activities.length} activities for Priya`);

        for (const a of activities.slice(0, 5)) {
            console.log(`     ${a.activityType} | ${a.summary}`);
        }
        if (activities.length > 5) console.log(`     ... and ${activities.length - 5} more`);
    }

    // ═══════════════════════════════════════
    // STEP 8: Simulate AI context assembly
    // ═══════════════════════════════════════
    console.log('\n8️⃣  AI CONTEXT ASSEMBLY');
    console.log('  What the AI assistant would receive:\n');
    console.log(`  Caller: ${matchedLead?.contactName?.firstName} ${matchedLead?.contactName?.lastName}`);
    console.log(`  Phone: ${CALLER_PHONE}`);
    console.log(`  Status: ${matchedLead?.status}`);
    console.log(`  Service: ${matchedLead?.interestedService}`);
    console.log(`  AI Summary: ${matchedLead?.aiSummary}`);
    console.log(`  Suggested Action: ${matchedLead?.aiSuggestedAction}`);
    console.log(`  Doctor: Dr. Patel — ${drPatel?.specialty}`);
    console.log(`  Next Appointment: ${drPatel?.visitingHours} at ${drPatel?.clinic?.clinicName ?? 'N/A'}`);
    console.log(`  Fee: ₹${(drPatel?.consultationFeeNew?.amountMicros ?? 0) / 1_000_000} (new) / ₹${(drPatel?.consultationFeeFollowUp?.amountMicros ?? 0) / 1_000_000} (follow-up)`);

    // ═══════════════════════════════════════
    // STEP 9: Test AI chat endpoint (if sidecar is running)
    // ═══════════════════════════════════════
    console.log('\n9️⃣  AI CHAT (via sidecar — skipped if not running)');
    try {
        const aiRes = await fetch('http://localhost:4100/api/ai/chat', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
            body: JSON.stringify({
                message: 'Tell me about the patient on the line. When is their next appointment?',
                context: { callerPhone: CALLER_PHONE, leadId, leadName: `${matchedLead?.contactName?.firstName} ${matchedLead?.contactName?.lastName}` },
            }),
            signal: AbortSignal.timeout(15000),
        });
        if (aiRes.ok) {
            const aiData = await aiRes.json();
            assert(!!aiData.reply, 'AI responded');
            console.log(`\n  🤖 AI says:\n  "${aiData.reply}"\n`);
            assert(aiData.sources?.length > 0, `Sources: ${aiData.sources?.join(', ')}`);
        } else {
            console.log(`  ⏭️  Sidecar returned ${aiRes.status} — skipping AI test`);
        }
    } catch {
        console.log('  ⏭️  Sidecar not running — AI chat test skipped');
    }

    // ═══════════════════════════════════════
    // RESULTS
    // ═══════════════════════════════════════
    console.log('\n' + '═'.repeat(50));
    if (failures === 0) {
        console.log('🎉 ALL TESTS PASSED');
    } else {
        console.log(`⚠️  ${failures} test(s) failed`);
    }
    console.log('═'.repeat(50));
}

main().catch(e => { console.error('💥', e.message); process.exit(1); });
