"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.representativesService = void 0;
const client_1 = require("@prisma/client");
const database_1 = require("../../../config/database");
const logger_1 = require("../../../utils/logger");
const error_handler_1 = require("../../../middleware/error-handler");
const represent_api_client_1 = require("./represent-api.client");
const postal_codes_service_1 = require("../postal-codes/postal-codes.service");
function deduplicateReps(reps) {
    const seen = new Set();
    return reps.filter((rep) => {
        const key = `${rep.name}|${rep.elected_office}`;
        if (seen.has(key))
            return false;
        seen.add(key);
        return true;
    });
}
exports.representativesService = {
    async lookupByPostalCode(code, forceRefresh = false) {
        // 1. Check cache unless forcing refresh
        if (!forceRefresh) {
            const cached = await database_1.prisma.representative.findMany({
                where: { postalCode: code },
            });
            if (cached.length > 0) {
                const postalInfo = await postal_codes_service_1.postalCodesService.findByPostalCode(code);
                return {
                    source: 'cache',
                    postalCode: code,
                    location: {
                        city: postalInfo?.city ?? null,
                        province: postalInfo?.province ?? null,
                    },
                    representatives: cached,
                };
            }
        }
        // 2. Call Represent API
        const apiResponse = await represent_api_client_1.representApiClient.getByPostalCode(code);
        // Merge centroid + concordance reps and deduplicate
        const allReps = [
            ...(apiResponse.representatives_centroid || []),
            ...(apiResponse.representatives_concordance || []),
        ];
        const uniqueReps = deduplicateReps(allReps);
        // 3. Fire-and-forget cache write
        const cacheWrite = async () => {
            try {
                // Delete old cached reps for this postal code
                await database_1.prisma.representative.deleteMany({ where: { postalCode: code } });
                // Cache new reps
                if (uniqueReps.length > 0) {
                    await database_1.prisma.representative.createMany({
                        data: uniqueReps.map((rep) => ({
                            postalCode: code,
                            name: rep.name || null,
                            email: rep.email || null,
                            districtName: rep.district_name || null,
                            electedOffice: rep.elected_office || null,
                            partyName: rep.party_name || null,
                            representativeSetName: rep.representative_set_name || null,
                            url: rep.url || null,
                            photoUrl: rep.photo_url || null,
                            offices: rep.offices ? rep.offices : client_1.Prisma.JsonNull,
                        })),
                    });
                }
                // Upsert postal code cache
                const coords = apiResponse.centroid?.coordinates;
                await postal_codes_service_1.postalCodesService.upsert({
                    postalCode: code,
                    city: apiResponse.city,
                    province: apiResponse.province,
                    centroidLat: coords ? coords[1] : null,
                    centroidLng: coords ? coords[0] : null,
                });
            }
            catch (err) {
                logger_1.logger.error('Failed to cache representatives', { postalCode: code, error: err });
            }
        };
        // Don't await — fire and forget
        cacheWrite();
        // 4. Build response from API data
        return {
            source: 'api',
            postalCode: code,
            location: {
                city: apiResponse.city ?? null,
                province: apiResponse.province ?? null,
            },
            representatives: uniqueReps.map((rep) => ({
                id: null,
                postalCode: code,
                name: rep.name || null,
                email: rep.email || null,
                districtName: rep.district_name || null,
                electedOffice: rep.elected_office || null,
                partyName: rep.party_name || null,
                representativeSetName: rep.representative_set_name || null,
                url: rep.url || null,
                photoUrl: rep.photo_url || null,
                offices: rep.offices ?? null,
                cachedAt: new Date().toISOString(),
            })),
        };
    },
    async findAll(filters) {
        const { page, limit, search, postalCode } = filters;
        const skip = (page - 1) * limit;
        const where = {};
        if (postalCode) {
            where.postalCode = postalCode;
        }
        if (search) {
            where.OR = [
                { name: { contains: search, mode: 'insensitive' } },
                { email: { contains: search, mode: 'insensitive' } },
                { districtName: { contains: search, mode: 'insensitive' } },
                { electedOffice: { contains: search, mode: 'insensitive' } },
            ];
        }
        const [representatives, total] = await Promise.all([
            database_1.prisma.representative.findMany({
                where,
                skip,
                take: limit,
                orderBy: { cachedAt: 'desc' },
            }),
            database_1.prisma.representative.count({ where }),
        ]);
        return {
            representatives,
            pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
        };
    },
    async findById(id) {
        const rep = await database_1.prisma.representative.findUnique({ where: { id } });
        if (!rep) {
            throw new error_handler_1.AppError(404, 'Representative not found', 'REPRESENTATIVE_NOT_FOUND');
        }
        return rep;
    },
    async clearByPostalCode(code) {
        const result = await database_1.prisma.representative.deleteMany({
            where: { postalCode: code },
        });
        return { deleted: result.count, postalCode: code };
    },
    async deleteById(id) {
        const existing = await database_1.prisma.representative.findUnique({ where: { id } });
        if (!existing) {
            throw new error_handler_1.AppError(404, 'Representative not found', 'REPRESENTATIVE_NOT_FOUND');
        }
        await database_1.prisma.representative.delete({ where: { id } });
    },
    async testApiConnection() {
        return represent_api_client_1.representApiClient.testConnection();
    },
    async getCacheStats() {
        const [totalReps, postalCodesWithReps, totalPostalCodes] = await Promise.all([
            database_1.prisma.representative.count(),
            database_1.prisma.representative.groupBy({ by: ['postalCode'] }).then((g) => g.length),
            database_1.prisma.postalCodeCache.count(),
        ]);
        return {
            totalRepresentatives: totalReps,
            postalCodesWithRepresentatives: postalCodesWithReps,
            totalPostalCodes,
        };
    },
};
//# sourceMappingURL=representatives.service.js.map