/**
 * SLA lifecycle: start → breach → geography escalation → pause/resume
 */

import { SLAService } from '../services/SLAService.js';
import { resolveRecipientsForRoles } from '../services/slaGeographyResolver.js';
import { NotificationService } from '../services/NotificationService.js';

const mockTrackUpdate = jest.fn().mockResolvedValue(true);
const mockTrackCreate = jest.fn().mockResolvedValue({ id: 'track-1', stageName: 'ASM Review', metadata: {} });
const mockFindAllTracks = jest.fn();
const mockBreachCreate = jest.fn().mockResolvedValue({ id: 'breach-1' });

const mockConfig = {
    id: 'cfg-1',
    activityName: 'ASM Review',
    tatHours: 1,
    tatUnit: 'hours',
    ownerRole: 'ASM,RBM',
    reminders: [],
    escalationConfigs: [{ level: 1, timeValue: 0, timeUnit: 'hours', notifyRole: 'RBM' }]
};

jest.mock('../database/models/index.js', () => {
    const mockUpdate = jest.fn().mockResolvedValue(true);
    return {
        default: {
            SLATracking: {
                findAll: (...args) => mockFindAllTracks(...args),
                update: mockUpdate,
                create: mockTrackCreate
            },
            SLAConfiguration: {
                findOne: jest.fn().mockResolvedValue(mockConfig),
                findByPk: jest.fn().mockResolvedValue({
                    ...mockConfig,
                    reminders: [],
                    escalationConfigs: mockConfig.escalationConfigs
                })
            },
            SLABreach: { create: (...args) => mockBreachCreate(...args) },
            Application: { findByPk: jest.fn().mockResolvedValue(null) },
            User: {
                findByPk: jest.fn().mockResolvedValue({ id: 'u-rbm', email: 'rbm@test.com', mobileNumber: '99' }),
                findAll: jest.fn().mockResolvedValue([]),
                findOne: jest.fn().mockResolvedValue(null)
            },
            Worknote: { create: jest.fn().mockResolvedValue(true) },
            TerminationRequest: { findByPk: jest.fn() },
            Resignation: { findByPk: jest.fn() },
            RelocationRequest: { findByPk: jest.fn() },
            ConstitutionalChange: { findByPk: jest.fn() },
            FnF: { findByPk: jest.fn() },
            Dealer: { findByPk: jest.fn() },
            Outlet: { findOne: jest.fn() },
            District: {},
            Region: {},
            Zone: {}
        },
        __mocks__: { mockUpdate, mockTrackUpdate }
    };
});

jest.mock('../common/config/slaStageCatalog.js', () => ({
    slaConfigLookupNames: (name) => [name]
}));

jest.mock('../common/utils/slaBusinessTime.js', () => ({
    effectiveElapsedMs: () => 10 * 60 * 60 * 1000
}));

jest.mock('../services/NotificationService.js', () => ({
    NotificationService: { notify: jest.fn().mockResolvedValue(undefined) }
}));

jest.mock('../services/slaGeographyResolver.js', () => ({
    resolveRecipientsForRoles: jest.fn().mockResolvedValue(['geo-rbm-1'])
}));

jest.mock('../common/utils/workflowWorknote.js', () => ({
    writeWorkflowActivityWorknote: jest.fn().mockResolvedValue(undefined)
}));

const mockNotify = jest.spyOn(NotificationService, 'notify').mockResolvedValue(undefined);
const mockGeo = resolveRecipientsForRoles;

describe('SLAService lifecycle', () => {
    beforeEach(() => {
        jest.clearAllMocks();
        process.env.DEBUG_SLA_FAST_MODE = 'true';
        mockFindAllTracks.mockReset();
    });

    it('startTrack creates a row when config exists', async () => {
        await SLAService.startTrack({
            entityType: 'application',
            entityId: 'app-1',
            applicationId: 'app-1',
            stageName: 'ASM Review'
        });
        expect(mockTrackCreate).toHaveBeenCalled();
    });

    it('checkBreaches triggers breach and geography-aware escalation', async () => {
        const track = {
            id: 'track-1',
            entityType: 'termination',
            entityId: 'term-1',
            applicationId: null,
            stageName: 'ASM Review',
            startTime: new Date(Date.now() - 3 * 60 * 60 * 1000),
            isBreached: false,
            isActive: true,
            endTime: null,
            metadata: {},
            update: mockTrackUpdate
        };

        mockFindAllTracks.mockResolvedValueOnce([track]).mockResolvedValueOnce([{ ...track, isBreached: true }]);

        await SLAService.checkBreaches();
        expect(mockBreachCreate).toHaveBeenCalled();
        expect(mockNotify).toHaveBeenCalled();

        await SLAService.checkBreaches();
        expect(mockGeo).toHaveBeenCalled();
    });

    it('pauseEntityTracks and resumeEntityTracks adjust metadata', async () => {
        const track = {
            id: 'track-2',
            metadata: {},
            update: jest.fn().mockImplementation(async (payload) => {
                track.metadata = payload.metadata;
            })
        };
        mockFindAllTracks.mockResolvedValue([track]);

        await SLAService.pauseEntityTracks('termination', 'term-1');
        expect(track.metadata.pausedAt).toBeDefined();

        await new Promise((r) => setTimeout(r, 5));
        await SLAService.resumeEntityTracks('termination', 'term-1');
        expect(track.metadata.pausedAt).toBeUndefined();
        expect(Number(track.metadata.accumulatedPauseMs || 0)).toBeGreaterThanOrEqual(0);
    });
});
