
import { test, expect } from './fixtures';
import { randomUUID } from 'crypto';

// Helper for setup
async function loginAndSetup(page: any, createUniqueUser: any) {
    const user = await createUniqueUser();
    await page.goto('/');
    await page.getByLabel('Email').fill(user.email);
    await page.getByLabel('Password').fill(user.password);
    await page.getByRole('button', { name: 'Login' }).click();

    try {
        const heading = page.getByRole('heading', { name: /Change Password/i });
        const dashboard = page.getByText('Free Workout');
        await expect(heading.or(dashboard)).toBeVisible({ timeout: 5000 });
        if (await heading.isVisible()) {
            await page.getByLabel('New Password').fill('StrongNewPass123!');
            await page.getByRole('button', { name: /Save|Change/i }).click();
            await expect(dashboard).toBeVisible();
        }
    } catch (e) {
        // Login might already be done
    }
    return user;
}

test.describe('IV. Data & Progress', () => {

    test('4.1. A. Session History - View Past Sessions', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);

        const exNameSession = 'Hist View Session ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exNameSession, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout|Start Empty/i }).click();
        await page.getByRole('textbox', { name: /Select Exercise/i }).click();
        await page.getByText(exNameSession).click();
        await page.getByLabel('Weight (kg)').first().fill('50');
        await page.getByLabel('Reps').first().fill('10');
        await page.getByRole('button', { name: /Log Set/i }).click();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        const exNameSporadic = 'Hist View Sporadic ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exNameSporadic, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: 'Quick Log' }).click();
        await page.getByRole('textbox', { name: /Select Exercise/i }).click();
        await page.getByText(exNameSporadic).click();
        await page.getByLabel(/Reps/i).first().fill('12');
        await page.getByRole('button', { name: /Log Set/i }).click();
        await page.getByRole('button', { name: 'Quit' }).click();

        await page.getByRole('button', { name: 'History' }).click();

        await expect(page.getByRole('heading', { name: 'History' })).toBeVisible();
        await expect(page.getByText(/50\s*kg\s*x\s*12\s*reps/).or(page.getByText(/x 12 reps/))).toBeVisible();
        await expect(page.getByText('No plan').first()).toBeVisible();
        await expect(page.getByText('Sets:').first()).toBeVisible();
        await expect(page.getByRole('heading', { name: 'Quick Log' })).toBeVisible();
    });

    test('4.2. A. Session History - View Detailed Session', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Detail View ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout|Start Empty/i }).click();
        await page.getByRole('textbox', { name: /Select Exercise/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel('Weight (kg)').first().fill('50');
        await page.getByLabel('Reps').first().fill('10');
        await page.getByRole('button', { name: /Log Set/i }).click();
        await page.getByRole('button', { name: 'Finish' }).click();
        // Wait for session save to complete
        const savePromise = page.waitForResponse(resp => resp.url().endsWith('/sessions/active') && resp.request().method() === 'PUT');
        await page.getByRole('button', { name: 'Confirm' }).click();
        const saveResp = await savePromise;
        if (!saveResp.ok()) console.log('Save failed:', await saveResp.text());
        expect(saveResp.ok()).toBeTruthy();

        await page.getByRole('button', { name: 'History' }).click();
        await page.getByText('No plan').first().click();

        await expect(page.getByRole('heading', { name: /Edit|Session Details/ })).toBeVisible();
        await expect(page.getByText('Start')).toBeVisible();
        await expect(page.getByText('End')).toBeVisible();
    });

    test('4.3. A. Session History - Edit Past Session Details', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Edit Sess ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        // Wait for session save to complete
        const savePromise = page.waitForResponse(resp => resp.url().endsWith('/sessions/active') && resp.request().method() === 'PUT');
        await page.getByRole('button', { name: 'Confirm' }).click();
        const saveResp = await savePromise;
        if (!saveResp.ok()) console.log('Save failed:', await saveResp.text());
        expect(saveResp.ok()).toBeTruthy();

        await page.getByRole('button', { name: 'History' }).click();
        await page.getByText('No plan').first().click();

        await page.getByRole('spinbutton').first().fill('75.5');
        await page.getByRole('button', { name: 'Save' }).click();

        await expect(page.getByText('75.5kg')).toBeVisible();
    });

    test('4.4. A. Session History - Edit Individual Set in Past Session', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Edit Set ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: `Log Set` }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        await page.getByRole('button', { name: 'History' }).click();
        await page.getByText('No plan').first().click();

        // Click the pencil icon to edit the set
        await page.getByRole('button', { name: 'Edit' }).first().click();

        // Find the input with value 50. It might be a number input.
        // Also wait for the input to be visible first
        await expect(page.locator('input[value="50"]')).toBeVisible();
        await page.locator('input[value="50"]').fill('55');
        await page.getByRole('button', { name: 'Save' }).last().click();

        await expect(page.getByText('55 kg x 10 reps')).toBeVisible();
    });

    test('4.5. A. Session History - Verify Edit Fields per Exercise Type', async ({ page, createUniqueUser, request }) => {
        // Merged from repro_edit_fields.spec.ts
        const user = await loginAndSetup(page, createUniqueUser);

        const types = [
            { type: 'PLYOMETRIC', name: 'Plyo Test', expectedFields: ['Reps'] },
            { type: 'STRENGTH', name: 'Strength Test', expectedFields: ['Weight (kg)', 'Reps'] },
            { type: 'CARDIO', name: 'Cardio Test', expectedFields: ['Time (sec)', 'Distance (m)'] },
            { type: 'STATIC', name: 'Static Test', expectedFields: ['Time (sec)', 'Weight (kg)', 'Body Weight'] },
            { type: 'BODYWEIGHT', name: 'Bodyweight Test', expectedFields: ['Reps', 'Body Weight', 'Weight (kg)'] },
            { type: 'HIGH_JUMP', name: 'High Jump Test', expectedFields: ['Height (cm)'] },
            { type: 'LONG_JUMP', name: 'Long Jump Test', expectedFields: ['Distance (m)'] },
        ];

        const exIds: Record<string, string> = {};

        for (const t of types) {
            const resp = await request.post('/api/exercises', {
                data: { name: t.name, type: t.type },
                headers: { 'Authorization': `Bearer ${user.token}` }
            });
            expect(resp.ok()).toBeTruthy();
            const created = await resp.json();
            exIds[t.name] = created.data?.id;
        }

        await page.reload();

        const now = Date.now();
        const setsStub = types.map(t => {
            const set: any = {
                exerciseId: exIds[t.name],
                timestamp: now + 1000,
                completed: true
            };
            if (t.type === 'STRENGTH' || t.type === 'BODYWEIGHT' || t.type === 'PLYOMETRIC') set.reps = 10;
            if (t.type === 'STRENGTH' || t.type === 'BODYWEIGHT' || t.type === 'STATIC') set.weight = 50;
            if (t.type === 'BODYWEIGHT' || t.type === 'STATIC') set.bodyWeightPercentage = 100;
            if (t.type === 'CARDIO' || t.type === 'STATIC') set.durationSeconds = 60;
            if (t.type === 'CARDIO' || t.type === 'LONG_JUMP') set.distanceMeters = 100;
            if (t.type === 'HIGH_JUMP') set.height = 150;
            return set;
        });

        const sessionResp = await request.post('/api/sessions', {
            data: {
                id: randomUUID(), // Required by saveSession service
                startTime: now,
                endTime: now + 3600000,
                type: 'STANDARD',
                sets: setsStub
            },
            headers: { 'Authorization': `Bearer ${user.token}` }
        });
        if (!sessionResp.ok()) console.log('Session create failed:', await sessionResp.json());
        expect(sessionResp.ok()).toBeTruthy();

        await page.getByRole('button', { name: 'History' }).first().click();
        // Click Session Actions menu button, then Edit from dropdown
        await page.getByRole('button', { name: 'Session Actions' }).click();
        await page.getByRole('button', { name: /Edit/i }).click();
        await expect(page.getByText('Edit', { exact: true })).toBeVisible();

        for (const t of types) {
            // Find the set row in the session edit dialog
            const row = page.locator('.bg-surface-container-low').filter({ hasText: t.name }).first();
            await expect(row).toBeVisible();

            // Click the Edit button for this specific set to open the set edit modal
            await row.getByRole('button', { name: /Edit/i }).click();

            // Wait for Edit Set modal to open
            await expect(page.getByRole('heading', { name: 'Edit Set' })).toBeVisible();

            // Get the Edit Set dialog to scope our searches
            const editSetDialog = page.getByRole('dialog').filter({ hasText: 'Edit Set' });

            // Verify the expected field labels are present in the modal
            for (const field of t.expectedFields) {
                // Use exact matching to avoid ambiguity (e.g., 'Time' vs 'Time (sec)')
                await expect(editSetDialog.getByText(field, { exact: true })).toBeVisible();
            }

            // Close the set edit modal before moving to the next set
            await page.getByRole('dialog').filter({ hasText: 'Edit Set' }).getByRole('button', { name: /Close/i }).click();
        }
    });

    test('4.6. A. Session History - Delete Past Session', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Del Sess ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        // Wait for session save to complete
        const savePromise = page.waitForResponse(resp => resp.url().endsWith('/sessions/active') && resp.request().method() === 'PUT');
        await page.getByRole('button', { name: 'Confirm' }).click();
        const saveResp = await savePromise;
        if (!saveResp.ok()) console.log('Save failed:', await saveResp.text());
        expect(saveResp.ok()).toBeTruthy();

        await page.getByRole('button', { name: 'History' }).click();

        // Open session menu and delete
        await page.getByRole('button', { name: 'Session Actions' }).first().click();
        await page.getByRole('button', { name: 'Delete', exact: true }).filter({ hasText: 'Delete' }).first().click(); // Click delete in menu
        await page.getByRole('button', { name: 'Delete', exact: true }).last().click(); // Click delete in confirmation modal
        await expect(page.getByText('History is empty')).toBeVisible();
    });

    test('4.7. A. Session History - Edit Sporadic Set', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Spor Edit ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: 'Quick Log' }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('12');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 12 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Quit' }).click();

        await page.getByRole('button', { name: 'History' }).click();
        await page.getByRole('button', { name: /Edit/i }).first().click(); // Edit

        await expect(page.getByRole('heading', { name: `Edit Set` })).toBeVisible();
        await page.locator('input[value="12"]').fill('15');
        await page.getByRole('button', { name: 'Save' }).click();

        await expect(page.getByText(/50\s*kg\s*x\s*15\s*reps/)).toBeVisible();
    });

    test('4.8. A. Session History - Delete Sporadic Set', async ({ page, createUniqueUser, request }) => {
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Spor Del ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: 'Quick Log' }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('12');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 12 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Quit' }).click();

        await page.getByRole('button', { name: 'History' }).click();
        await page.getByRole('button', { name: /Delete/i }).first().click(); // Delete icon
        // Scope to dialog to avoid finding the icon button behind it
        await page.getByRole('dialog').getByRole('button', { name: 'Delete' }).click(); // Confirm delete

        await expect(page.getByText('50 kg x 12 reps')).not.toBeVisible();
    });

    test('4.9. A. Session History - Export CSV', async ({ page, createUniqueUser, request }) => {
        // Merged from history-export.spec.ts
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Bench Press Test';
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: 'Free Workout' }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByText(exName).first().click();
        await page.getByLabel(/Weight/i).first().fill('100');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: 'Log Set' }).click();
        await expect(page.getByText('100 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        await page.getByRole('button', { name: 'History' }).click();
        const downloadPromise = page.waitForEvent('download');
        await page.getByRole('button', { name: 'Export CSV' }).click();
        const download = await downloadPromise;

        expect(download.suggestedFilename()).toContain('gymflow_history');
        expect(download.suggestedFilename()).toContain('.csv');
    });

    test('4.10. B. Performance Statistics - View Volume Chart', async ({ page, createUniqueUser, request }) => {
        test.setTimeout(120000);
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Vol Chart ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        // Session 1
        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        // Session 2
        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('60');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('60 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        await page.getByRole('button', { name: 'Stats' }).click();
        await expect(page.getByText('Work Volume')).toBeVisible();
    });

    test('4.11. B. Performance Statistics - View Set Count Chart', async ({ page, createUniqueUser, request }) => {
        test.setTimeout(120000);
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'Set Chart ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        // Session 1
        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        // Session 2
        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('60');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('60 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        await page.getByRole('button', { name: 'Stats' }).click();
        await expect(page.getByText('Number of Sets')).toBeVisible();
    });

    test('4.12. B. Performance Statistics - View Body Weight Chart', async ({ page, createUniqueUser, request }) => {
        test.setTimeout(120000);
        const user = await loginAndSetup(page, createUniqueUser);
        const exName = 'BW Chart ' + randomUUID().slice(0, 4);
        await request.post('/api/exercises', { data: { name: exName, type: 'STRENGTH' }, headers: { 'Authorization': `Bearer ${user.token}` } });

        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        // Second session to satisfy "Not enough data" check
        await page.getByRole('button', { name: /Free Workout/i }).click();
        await page.getByRole('textbox', { name: /Select/i }).click();
        await page.getByRole('button', { name: exName }).click();
        await page.getByLabel(/Weight/i).first().fill('50');
        await page.getByLabel(/Reps/i).first().fill('10');
        await page.getByRole('button', { name: /Log/i }).click();
        await expect(page.getByText('50 kg x 10 reps')).toBeVisible();
        await page.getByRole('button', { name: 'Finish' }).click();
        await page.getByRole('button', { name: 'Confirm' }).click();

        const yesterday = new Date();
        yesterday.setDate(yesterday.getDate() - 1);
        const dateStr = yesterday.toISOString().split('T')[0];

        await page.evaluate(async ({ token, dateStr }) => {
            await fetch('/api/weight', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
                body: JSON.stringify({ weight: 70, dateStr })
            });
        }, { token: user.token, dateStr });

        await page.getByRole('button', { name: 'Profile' }).click();
        await page.getByRole('button', { name: 'Weight Tracker' }).click();
        await page.getByPlaceholder('Enter weight...').fill('72');
        await page.getByRole('button', { name: 'Log', exact: true }).click();
        await expect(page.getByText('Weight logged successfully')).toBeVisible();

        await page.getByRole('button', { name: 'Stats' }).click();
        await expect(page.getByText('Body Weight History')).toBeVisible();
    });

});
