import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateFollowupDto } from './dto/create-followup.dto';
import { NotificationsService } from '../notifications/notifications.service';
import { WhatsappService } from '../whatsapp/whatsapp.service';

@Injectable()
export class FollowupsService {
    constructor(
        private prisma: PrismaService,
        private notifications: NotificationsService,
        private whatsappService: WhatsappService
    ) { }

    // Auto-transition pipeline opportunity stage forward
    private async autoTransitionStage(opportunityId: string, newStage: 'QUALIFIED' | 'POTENTIAL' | 'SALES') {
        try {
            const current = await this.prisma.opportunity.findUnique({
                where: { id: opportunityId },
                include: { client: true }
            });
            if (!current) return;

            const stagesOrder = { LEAD: 1, QUALIFIED: 2, POTENTIAL: 3, SALES: 4, LOST: 0 };
            const currentPriority = stagesOrder[current.stage] || 0;
            const newPriority = stagesOrder[newStage] || 0;

            // Only transition forward
            if (newPriority > currentPriority) {
                const updated = await this.prisma.opportunity.update({
                    where: { id: opportunityId },
                    data: { stage: newStage, updatedAt: new Date() },
                    include: { client: true }
                });

                console.log(`[AUTO-STAGE] Transitioned opportunity ${opportunityId} from ${current.stage} to ${newStage}`);

                try {
                    await this.whatsappService.sendPipelineUpdate(
                        updated.client.phone,
                        updated.client.name,
                        current.stage,
                        updated.stage
                    );
                } catch (err) {
                    console.error('Failed to send pipeline WhatsApp on auto-transition:', err.message);
                }
            }
        } catch (err) {
            console.error('Error during auto-transition of opportunity stage:', err);
        }
    }

    private async evaluateStageTransitions(followup: any) {
        let opportunityIds: string[] = [];

        if (followup.opportunityId) {
            opportunityIds.push(followup.opportunityId);
        } else if (followup.clientId) {
            // Fallback: If opportunityId is null, resolve all open opportunities of the client
            try {
                const clientOpps = await this.prisma.opportunity.findMany({
                    where: {
                        clientId: followup.clientId,
                        stage: { in: ['LEAD', 'QUALIFIED', 'POTENTIAL'] }
                    },
                    select: { id: true }
                });
                opportunityIds = clientOpps.map(o => o.id);
            } catch (err) {
                console.error('Failed to look up client opportunities for stage transition fallback:', err);
            }
        }

        if (opportunityIds.length === 0) return;

        const type = followup.type;

        try {
            for (const opportunityId of opportunityIds) {
                if (['QUOTE_SEND', 'QUOTE', 'QUOTE_REQUEST', 'SECOND_QUOTE'].includes(type)) {
                    // Count previous quotes and activities of this type
                    const prevQuotesCount = await this.prisma.quote.count({
                        where: { opportunityId }
                    });
                    const prevQuoteActivities = await this.prisma.followup.count({
                        where: {
                            opportunityId,
                            id: { not: followup.id },
                            type: { in: ['QUOTE_SEND', 'QUOTE', 'QUOTE_REQUEST', 'SECOND_QUOTE'] }
                        }
                    });

                    if (prevQuotesCount + prevQuoteActivities >= 1) {
                        await this.autoTransitionStage(opportunityId, 'SALES');
                    } else {
                        await this.autoTransitionStage(opportunityId, 'QUALIFIED');
                    }
                } else if (['DEMO_SCHEDULED', 'DEMO_COMPLETED', 'DEMO', 'SECOND_DEMO'].includes(type)) {
                    // Count previous demos
                    const prevDemoActivities = await this.prisma.followup.count({
                        where: {
                            opportunityId,
                            id: { not: followup.id },
                            type: { in: ['DEMO_SCHEDULED', 'DEMO_COMPLETED', 'DEMO', 'SECOND_DEMO'] }
                        }
                    });

                    if (prevDemoActivities >= 1) {
                        await this.autoTransitionStage(opportunityId, 'SALES');
                    } else {
                        await this.autoTransitionStage(opportunityId, 'POTENTIAL');
                    }
                } else if (['VISIT_SCHEDULED', 'VISIT_COMPLETED'].includes(type)) {
                    await this.autoTransitionStage(opportunityId, 'SALES');
                }
                
                // If it's a mutation activity marked as DONE
                if (followup.status === 'DONE') {
                    if (type === 'TIMEFRAME_UPDATE' && followup.expectedClosingTimeframe) {
                        await this.prisma.opportunity.update({
                            where: { id: opportunityId },
                            data: { expectedClosingTimeframe: followup.expectedClosingTimeframe }
                        });
                    }
                    if (type === 'PROBABILITY_UPDATE' && followup.notes) {
                        const parsedProb = parseFloat(followup.notes);
                        if (!isNaN(parsedProb)) {
                            await this.prisma.opportunity.update({
                                where: { id: opportunityId },
                                data: { closingProbability: parsedProb }
                            });
                        }
                    }
                }
            }
        } catch (err) {
            console.error('Error in evaluateStageTransitions:', err);
        }
    }

    async create(createFollowupDto: CreateFollowupDto) {
        // Map description to notes if provided, and exclude 'time' which is only used by the frontend
        const { description, time, ...rest } = createFollowupDto as any;
        const data = {
            ...rest,
            notes: rest.notes || description, // Use description if notes is empty
        };

        const followup = await this.prisma.followup.create({
            data,
            include: { client: true }
        });

        // Trigger WhatsApp followup reminder — fire-and-forget (non-blocking)
        if (followup.client?.phone) {
            this.whatsappService.sendFollowupReminder(
                followup.client.phone,
                followup.client.name,
                new Date(followup.date).toLocaleString()
            ).catch(err => console.error('Failed to send followup WhatsApp:', err.message));
        }

        // Send Alert to Assigned User — non-blocking
        if (data.userId) {
            this.notifications.create(
                data.userId,
                'New Follow-up Assigned 📅',
                `You have been assigned a new follow-up task for client. Deadline: ${new Date(data.date).toLocaleString()}`,
                'FOLLOWUP_ASSIGNED'
            ).catch(err => console.error('Failed to send notification:', err.message));
        }

        // Evaluate auto-stage transitions — fire-and-forget (non-blocking)
        this.evaluateStageTransitions(followup).catch(err =>
            console.error('Error in evaluateStageTransitions (non-blocking):', err)
        );

        return followup;
    }

    findAll(filters?: { userId?: string; clientId?: string; dateFrom?: string; dateTo?: string; status?: string; opportunityId?: string; enquiryId?: string }) {
        const where: any = {};
        if (filters?.userId) where.userId = filters.userId;
        if (filters?.clientId) where.clientId = filters.clientId;
        if (filters?.status) where.status = filters.status;
        if (filters?.opportunityId) where.opportunityId = filters.opportunityId;
        if (filters?.enquiryId) where.enquiryId = filters.enquiryId;
        if (filters?.dateFrom || filters?.dateTo) {
            where.date = {};
            if (filters.dateFrom) where.date.gte = new Date(filters.dateFrom);
            if (filters.dateTo) where.date.lte = new Date(filters.dateTo);
        }
        return this.prisma.followup.findMany({
            where,
            include: { client: true, user: true, enquiry: { include: { products: true } }, opportunity: true },
            orderBy: { date: 'asc' }
        });
    }

    findOne(id: string) {
        return this.prisma.followup.findUnique({
            where: { id },
            include: { client: true, user: true, enquiry: true }
        });
    }

    async update(id: string, updateFollowupDto: any) {
        // Fetch current state before update to detect reassignment
        const existing = await this.prisma.followup.findUnique({ where: { id } });

        // Extract extra fields that don't exist in Prisma schema to avoid database errors
        const schemaFields = [
            'id', 'clientId', 'enquiryId', 'userId', 'date', 'notes', 'status', 
            'createdAt', 'updatedAt', 'contentType', 'stage', 'competitorMention', 
            'demoContactDetails', 'demoPersonName', 'keyQueries', 'objections', 
            'opportunityId', 'type'
        ];

        const extraData: Record<string, any> = {};
        const prismaData: Record<string, any> = {};

        Object.keys(updateFollowupDto).forEach(key => {
            if (schemaFields.includes(key)) {
                prismaData[key] = updateFollowupDto[key];
            } else {
                extraData[key] = updateFollowupDto[key];
            }
        });

        // If there are extra feedback fields, format them nicely and append to 'notes'
        if (Object.keys(extraData).length > 0) {
            const feedbackSummary = Object.entries(extraData)
                .filter(([_, val]) => val !== undefined && val !== null && val !== '')
                .map(([key, val]) => {
                    const label = key
                        .replace(/([A-Z])/g, ' $1')
                        .replace(/^./, str => str.toUpperCase());
                    return `• ${label}: ${val}`;
                })
                .join('\n');

            if (feedbackSummary) {
                const originalNotes = existing?.notes || '';
                prismaData.notes = originalNotes 
                    ? `${originalNotes}\n\n[DEMO FEEDBACK LOG]\n${feedbackSummary}` 
                    : `[DEMO FEEDBACK LOG]\n${feedbackSummary}`;
            }
        }

        const followup = await this.prisma.followup.update({
            where: { id },
            data: prismaData,
            include: { user: true, client: true }
        });

        // Auto-dismiss notification when marked DONE
        if (updateFollowupDto.status === 'DONE' && followup.userId) {
            await this.prisma.$executeRaw`
                UPDATE notification 
                SET isRead = true 
                WHERE userId = ${followup.userId} 
                AND type = 'FOLLOWUP_ASSIGNED' 
                AND isRead = false
            `;
        }

        // Handle Reassignment — new userId provided and it's different from existing
        if (updateFollowupDto.userId && existing && updateFollowupDto.userId !== existing.userId) {
            // Dismiss old assignee's notification
            if (existing.userId) {
                await this.prisma.$executeRaw`
                    UPDATE notification SET isRead = true 
                    WHERE userId = ${existing.userId} AND type = 'FOLLOWUP_ASSIGNED' AND isRead = false
                `;
            }
            // Notify new assignee
            const deadline = new Date(followup.date).toLocaleString();
            await this.notifications.create(
                updateFollowupDto.userId,
                'Follow-up Reassigned to You 📅',
                `A follow-up task for ${followup.client?.name || 'a client'} has been reassigned to you. Deadline: ${deadline}`,
                'FOLLOWUP_ASSIGNED'
            );
        }

        // Auto-sync DEMO feedback to Opportunity
        if (updateFollowupDto.status === 'DONE' && (followup.type === 'DEMO' || followup.type === 'DEMO_COMPLETED') && followup.opportunityId) {
            await this.prisma.opportunity.update({
                where: { id: followup.opportunityId },
                data: {
                    isDemoDone: true,
                    demoPersonName: followup.demoPersonName,
                    demoContactDetails: followup.demoContactDetails,
                    keyQueries: followup.keyQueries,
                    competitorMention: followup.competitorMention
                }
            });
        }

        // Evaluate auto-stage transitions — only when explicitly marking DONE
        if (updateFollowupDto.status === 'DONE') {
            await this.evaluateStageTransitions(followup);
        }

        return followup;
    }

    remove(id: string) {
        return this.prisma.followup.delete({ where: { id } });
    }
}
