import React, { createContext, useContext, useEffect, useState, useMemo, useCallback } from 'react';
import { useAuth } from './AuthContext';
import { Employee, EmployeeReport, Submission, CompanyReport } from '../types';
import { SAMPLE_COMPANY_REPORT, API_URL } from '../constants';
import { apiPost, apiPut } from '../services/api';
import { User } from 'firebase/auth';
import { EmployeeSubmissionAnswers } from '../employeeQuestions';
import { secureApi } from '../services/secureApi';

interface OrgData {
    orgId: string;
    name?: string;
    companyName?: string;
    onboardingData?: Record<string, any>;
    companyLogo?: string;
    updatedAt?: number;
    onboardingCompleted?: boolean;
    ownerId?: string;
    ownerInfo?: {
        id: string;
        name: string;
        email: string;
        joinedAt: number;
    };
}

interface OrgContextType {
    org: OrgData | null;
    user?: User;
    orgId: string;
    employees: Employee[];
    submissions: Record<string, Submission>;
    reports: Record<string, EmployeeReport>;
    loading: boolean;
    upsertOrg: (data: Partial<OrgData>) => Promise<void>;
    saveReport: (employeeId: string, report: EmployeeReport) => Promise<void>;
    inviteEmployee: (args: { name: string; email: string }) => Promise<{ employeeId: string; inviteLink: string }>;
    issueInviteViaApi: (args: { name: string; email: string; role?: string; department?: string }) => Promise<{ code: string; inviteLink: string; employee: any }>;
    getInviteStatus: (code: string) => Promise<{ used: boolean; employee: any } | null>;
    consumeInvite: (code: string) => Promise<{ employee: any; orgId?: string } | null>;
    getReportVersions: (employeeId: string) => Promise<Array<{ id: string; createdAt: number; report: EmployeeReport }>>;
    saveReportVersion: (employeeId: string, report: EmployeeReport) => Promise<void>;
    acceptInvite: (code: string) => Promise<void>;
    saveCompanyReport: (summary: string) => Promise<void>;
    getCompanyReportHistory: () => Promise<Array<{ id: string; createdAt: number; summary: string }>>;
    saveFullCompanyReport: (report: CompanyReport) => Promise<void>;
    getFullCompanyReportHistory: () => Promise<CompanyReport[]>;
    generateCompanyReport: () => Promise<CompanyReport>;
    generateCompanyWiki: (orgOverride?: OrgData) => Promise<CompanyReport>;
    seedInitialData: () => Promise<void>;
    isOwner: (employeeId?: string) => boolean;
    submitEmployeeAnswers: (employeeId: string, answers: Record<string, string>) => Promise<any>;
    generateEmployeeReport: (employee: Employee) => Promise<EmployeeReport | null>;
    getEmployeeReport: (employeeId: string) => Promise<{ success: boolean; report?: EmployeeReport; error?: string }>;
    getEmployeeReports: () => Promise<{ success: boolean; reports?: EmployeeReport[]; error?: string }>;
}

const OrgContext = createContext<OrgContextType | undefined>(undefined);

export const OrgProvider: React.FC<{ children: React.ReactNode; selectedOrgId: string }> = ({ children, selectedOrgId }) => {
    const { user } = useAuth();
    const [org, setOrg] = useState<OrgData | null>(null);
    const [employees, setEmployees] = useState<Employee[]>([]);
    const [submissions, setSubmissions] = useState<Record<string, Submission>>({});
    const [reports, setReports] = useState<Record<string, EmployeeReport>>({});
    const [reportVersions, setReportVersions] = useState<Record<string, Array<{ id: string; createdAt: number; report: EmployeeReport }>>>({});
    const [companyReports, setCompanyReports] = useState<Array<{ id: string; createdAt: number; summary: string }>>([]);
    const [fullCompanyReports, setFullCompanyReports] = useState<CompanyReport[]>([]);
    const [loading, setLoading] = useState(true);

    // Use the provided selectedOrgId instead of deriving from user
    const orgId = selectedOrgId;

    // Load initial data using secure API - memoized to prevent unnecessary re-runs
    useEffect(() => {
        if (!orgId || !user?.uid) {
            setLoading(false);
            return;
        }

        console.log('OrgContext: Loading data via secure API for orgId:', orgId);

        const loadOrgData = async () => {
            try {
                setLoading(true);

                // Batch all API calls for better performance
                const [orgData, employeesData, submissionsData, reportsData, companyReportsData] = await Promise.allSettled([
                    secureApi.getOrgData().catch(() => null),
                    secureApi.getEmployees().catch(() => []),
                    secureApi.getSubmissions().catch(() => ({})),
                    secureApi.getReports().catch(() => ({})),
                    secureApi.getCompanyReports().catch(() => [])
                ]);

                // Process organization data
                if (orgData.status === 'fulfilled' && orgData.value) {
                    setOrg({ orgId, ...orgData.value });
                } else {
                    console.warn('Could not load org data, creating default');
                    const defaultOrg = { name: 'Your Company', onboardingCompleted: false };
                    await secureApi.updateOrgData(defaultOrg);
                    setOrg({ orgId, ...defaultOrg });
                }

                // Process employees data
                if (employeesData.status === 'fulfilled') {
                    setEmployees(employeesData.value.map(emp => ({
                        ...emp,
                        initials: emp.name ? emp.name.split(' ').map(n => n[0]).join('').toUpperCase() : emp.email?.substring(0, 2).toUpperCase() || 'U'
                    })));
                } else {
                    console.warn('Could not load employees');
                    setEmployees([]);
                }

                // Process submissions data
                if (submissionsData.status === 'fulfilled') {
                    setSubmissions(submissionsData.value);
                } else {
                    console.warn('Could not load submissions');
                    setSubmissions({});
                }

                // Process reports data
                if (reportsData.status === 'fulfilled') {
                    setReports(reportsData.value as Record<string, EmployeeReport>);
                } else {
                    console.warn('Could not load reports');
                    setReports({});
                }

                // Process company reports data
                if (companyReportsData.status === 'fulfilled') {
                    setFullCompanyReports(companyReportsData.value);
                } else {
                    console.warn('Could not load company reports');
                    setFullCompanyReports([]);
                }

            } catch (error) {
                console.error('Failed to load org data:', error);
            } finally {
                setLoading(false);
            }
        };

        loadOrgData();
    }, [orgId, user?.uid]); // Only re-run when orgId or user changes

    const upsertOrg = useCallback(async (data: Partial<OrgData>) => {
        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            await secureApi.updateOrgData(data);

            // Update local state
            const updatedOrg = { ...(org || { orgId, name: 'Your Company' }), ...data } as OrgData;
            setOrg(updatedOrg);

            // If onboarding was completed, notify other contexts
            if (data.onboardingCompleted) {
                console.log('OrgContext: Onboarding completed, dispatching update event', {
                    orgId: updatedOrg.orgId,
                    onboardingCompleted: true
                });

                window.dispatchEvent(new CustomEvent('organizationUpdated', {
                    detail: { orgId: updatedOrg.orgId, onboardingCompleted: true }
                }));
            }
        } catch (error) {
            console.error('Failed to update organization:', error);
            throw error;
        }
    }, [user?.uid, org, orgId]);

    const saveReport = useCallback(async (employeeId: string, report: EmployeeReport) => {
        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            const savedReport = await secureApi.saveReport(employeeId, report);

            // Update local state
            setReports(prev => ({ ...prev, [employeeId]: savedReport }));
        } catch (error) {
            console.error('Failed to save report:', error);
            throw error;
        }
    }, [user?.uid]);

    const inviteEmployee = async ({ name, email, role, department }: { name: string; email: string, role?: string, department?: string }) => {
        console.log('inviteEmployee called:', { name, email, orgId });

        try {
            // Use secure API for invites
            const data = await secureApi.createInvitation({ name, email, role, department });

            console.log('Invite created successfully:', { code: data.code, employee: data.employee.name, inviteLink: data.inviteLink });

            // Store employee locally for immediate UI update with proper typing
            const newEmployee: Employee = {
                id: data.employee.id,
                name: data.employee.name,
                email: data.employee.email,
                initials: data.employee.name ? data.employee.name.split(' ').map(n => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase(),
                department: data.employee.department,
                role: data.employee.role,
                status: data.employee.status
            };

            // Add to local state for immediate UI update
            setEmployees(prev => {
                if (prev.find(e => e.id === data.employee.id)) return prev;
                return [...prev, newEmployee];
            });

            return { employeeId: data.employee.id, inviteLink: data.inviteLink };
        } catch (error) {
            console.error('inviteEmployee error:', error);
            throw error;
        }
    };

    const getReportVersions = async (employeeId: string) => {
        // This feature is not yet implemented in secure API
        // Return empty array for now until we add version support to cloud functions
        console.warn('Report versions not yet supported in secure API');
        return [];
    };

    const saveReportVersion = async (employeeId: string, report: EmployeeReport) => {
        // This feature is not yet implemented in secure API
        console.warn('Report versions not yet supported in secure API');
        const version = { id: Date.now().toString(), createdAt: Date.now(), report };
        setReportVersions(prev => ({ ...prev, [employeeId]: [version, ...(prev[employeeId] || [])] }));
    };

    const acceptInvite = async (code: string) => {
        if (!code || !user?.uid) return;

        try {
            await secureApi.consumeInvitation(code, user.uid);
        } catch (error) {
            console.error('Failed to accept invite:', error);
            throw error;
        }
    };

    const saveCompanyReport = async (summary: string) => {
        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            const report = {
                id: Date.now().toString(),
                createdAt: Date.now(),
                summary
            };

            await secureApi.saveCompanyReport(report);

            // Update local state
            setCompanyReports(prev => [{ id: report.id, createdAt: report.createdAt, summary }, ...prev]);
        } catch (error) {
            console.error('Failed to save company report:', error);
            throw error;
        }
    };

    const getCompanyReportHistory = async () => {
        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            const reports = await secureApi.getCompanyReports();
            return reports.map(report => ({
                id: report.id,
                createdAt: report.createdAt || 0,
                summary: report.executiveSummary || ''
            })).sort((a, b) => b.createdAt - a.createdAt);
        } catch (error) {
            console.error('Failed to get company report history:', error);
            return [];
        }
    };

    const seedInitialData = async () => {
        // Start with clean slate - let users invite their own employees and generate real data
        setEmployees([]);
        setSubmissions({});
        setReports({});
        setFullCompanyReports([]);
    };

    const saveFullCompanyReport = async (report: CompanyReport) => {
        if (!orgId) {
            console.error('Cannot save company report: orgId is undefined');
            throw new Error('Organization ID is required to save company report');
        }

        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            await secureApi.saveCompanyReport(report);

            // Update local state after successful save
            setFullCompanyReports(prev => [report, ...prev]);
        } catch (error) {
            console.error('Failed to save full company report:', error);
            throw error;
        }
    };

    const getFullCompanyReportHistory = async (): Promise<CompanyReport[]> => {
        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        try {
            const reports = await secureApi.getCompanyReports();
            return reports.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
        } catch (error) {
            console.error('Failed to get full company report history:', error);
            return [];
        }
    };

    const generateCompanyReport = async (): Promise<CompanyReport> => {
        console.log('generateCompanyReport called for org:', orgId);

        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        // Calculate concrete metrics from actual data (no AI needed)
        // Employees collection only contains actual employees (owners are not in this collection)
        const actualEmployees = employees;
        const totalEmployees = actualEmployees.length;

        // Count submissions from employees
        const employeeSubmissions = submissions;
        const submittedEmployees = Object.keys(employeeSubmissions).length;
        const submissionRate = totalEmployees > 0 ? (submittedEmployees / totalEmployees) * 100 : 0;

        // Department breakdown (concrete data) - exclude owners
        const deptMap = new Map<string, number>();
        actualEmployees.forEach(emp => {
            const dept = emp.department || 'Unassigned';
            deptMap.set(dept, (deptMap.get(dept) || 0) + 1);
        });
        const departmentBreakdown = Array.from(deptMap.entries()).map(([department, count]) => ({ department, count }));

        let response, report: CompanyReport;

        try {
            // Use secure API for AI generation
            response = await secureApi.generateCompanyWiki({
                ...org,
                metrics: {
                    totalEmployees,
                    submissionRate,
                    departmentBreakdown
                }
            }, Object.values(employeeSubmissions));

            console.log('Company insights generated via AI successfully');

            // Combine concrete metrics with AI insights
            // report = {
            //     id: Date.now().toString(),
            //     createdAt: Date.now(),
            //     // Use AI-generated insights for subjective analysis
            //     // Override with our concrete metrics
            //     overview: {
            //         totalEmployees,
            //         departmentBreakdown,
            //         submissionRate,
            //         lastUpdated: Date.now(),
            //         averagePerformanceScore: (response as any)?.overview?.averagePerformanceScore || 0,
            //         riskLevel: (response as any)?.overview?.riskLevel || 'Unknown'
            //     },
            //     ...(response as any)
            // };

            console.log('Final company report object:', report);
            // await saveFullCompanyReport(report);
            return response;
        } catch (error) {
            console.error('generateCompanyReport error:', error);
            throw error;
        }
    };

    const generateCompanyWiki = async (orgOverride?: OrgData): Promise<CompanyReport> => {
        const orgData = orgOverride || org;
        console.log('generateCompanyWiki called with:', { orgData, orgId, submissionsCount: Object.keys(submissions || {}).length });

        if (!orgId) {
            throw new Error('Organization ID is required to generate company wiki');
        }

        if (!user?.uid) {
            throw new Error('User authentication required');
        }

        // Use secure API for wiki generation
        try {
            console.log('Making API call to generateCompanyWiki...');
            let response = await secureApi.generateCompanyWiki(orgData, Object.values(submissions || {}));

            console.log('API success response:', response);

            // Ensure the report has all required fields to prevent undefined errors
            const report: CompanyReport = {
                id: Date.now().toString(),
                createdAt: Date.now(),
                overview: {
                    totalEmployees: employees.length,
                    departmentBreakdown: [],
                    submissionRate: 0,
                    lastUpdated: Date.now(),
                    averagePerformanceScore: 0,
                    riskLevel: 'Unknown'
                },
                gradingBreakdown: [],
                personnelChanges: { newHires: [], promotions: [], departures: [] },
                immediateHiringNeeds: [],
                forwardOperatingPlan: { quarterlyGoals: [], resourceNeeds: [], riskMitigation: [] },
                executiveSummary: 'Company report generated successfully.',
                // Override with API data if available
                ...(response as any || {})
            };

            // await saveFullCompanyReport(data);
            return response;
        } catch (e) {
            console.error('generateCompanyWiki error, falling back to local synthetic:', e);
            return generateCompanyReport();
        }
    };

    const isOwner = (userId?: string): boolean => {
        // Check if the given user ID matches the org owner ID
        // If no userId provided, check current user
        const targetUserId = userId || user?.uid;
        return targetUserId === org?.ownerId;
    };

    const getEmployeeReport = async (employeeId: string) => {
        try {
            if (!user?.uid) {
                throw new Error('User authentication required');
            }

            // Use secure API for all employee report operations
            const report = await secureApi.getReports();
            const employeeReport = report[employeeId];

            if (employeeReport) {
                return { success: true, report: employeeReport };
            }
            return { success: false, error: 'Report not found' };
        } catch (error) {
            console.error('Error fetching employee report:', error);
            return { success: false, error: (error as Error).message };
        }
    };

    const getEmployeeReports = async () => {
        try {
            if (!user?.uid) {
                throw new Error('User authentication required');
            }

            // Use secure API for all employee report operations
            const reportsData = await secureApi.getReports();
            const reports = Object.values(reportsData);
            return { success: true, reports };
        } catch (error) {
            console.error('Error fetching employee reports:', error);
            return { success: false, error: (error as Error).message };
        }
    };

    // Memoize functions that don't need dependencies
    const issueInviteViaApi = useCallback(async ({ name, email, role, department }) => {
        try {
            if (!user?.uid) {
                throw new Error('User authentication required');
            }

            const data = await secureApi.createInvitation({ name, email, role, department });

            // Optimistically add employee shell (not yet active until consume)
            setEmployees(prev => prev.find(e => e.id === data.employee.id) ? prev : [...prev, {
                ...data.employee,
                initials: data.employee.name ? data.employee.name.split(' ').map((n: string) => n[0]).join('').toUpperCase() : data.employee.email.substring(0, 2).toUpperCase()
            } as Employee]);
            return data;
        } catch (e) {
            console.error('issueInviteViaApi error', e);
            throw e;
        }
    }, [user?.uid]);

    const getInviteStatus = useCallback(async (code: string) => {
        try {
            return await secureApi.getInvitationStatus(code);
        } catch (e) {
            console.error('getInviteStatus error', e);
            return null;
        }
    }, []);

    const consumeInvite = useCallback(async (code: string) => {
        try {
            if (!user?.uid) {
                throw new Error('User authentication required');
            }

            const result = await secureApi.consumeInvitation(code, user.uid);

            // Mark employee as active
            if (result && (result as any).employee) {
                setEmployees(prev => prev.find(e => e.id === (result as any).employee.id) ? prev : [...prev, (result as any).employee]);
                return { ...(result as any), orgId: org?.orgId };
            }
            return null;
        } catch (e) {
            console.error('consumeInvite error', e);
            return null;
        }
    }, [user?.uid, org?.orgId]);

    const submitEmployeeAnswers = useCallback(async (employeeId: string, answers: Record<string, string>) => {
        try {
            // Use secure API for submission
            await secureApi.submitEmployeeAnswers(employeeId, answers);

            // Update local state for immediate UI feedback
            const convertedSubmission: Submission = {
                employeeId,
                answers: Object.entries(answers).map(([question, answer]) => ({
                    question,
                    answer
                }))
            };
            setSubmissions(prev => ({ ...prev, [employeeId]: convertedSubmission }));
            return true;
        } catch (e) {
            console.error('submitEmployeeAnswers error', e);
            return false;
        }
    }, []);

    const generateEmployeeReport = useCallback(async (employee: Employee) => {
        try {
            console.log('generateEmployeeReport called for:', employee.name, 'in org:', orgId);

            if (!user?.uid) {
                throw new Error('User authentication required');
            }

            // Get submission data for this employee
            const submission = submissions[employee.id];
            if (!submission) {
                throw new Error(`No questionnaire submission found for ${employee.name}. Please ensure they have completed the employee questionnaire first.`);
            }

            // Convert submission format for API
            let submissionAnswers: Record<string, string> = {};
            if (submission.answers) {
                if (Array.isArray(submission.answers)) {
                    // If answers is an array of {question, answer} objects
                    submissionAnswers = submission.answers.reduce((acc, item: any) => {
                        acc[item.question] = item.answer;
                        return acc;
                    }, {} as Record<string, string>);
                } else {
                    // If answers is already a key-value object
                    submissionAnswers = submission.answers as Record<string, string>;
                }
            }

            console.log('Submission data found:', Object.keys(submissionAnswers).length, 'answers');

            // Get company report and wiki data for context
            let companyWiki = null;
            try {
                const companyReports = await getFullCompanyReportHistory();
                if (companyReports.length > 0) {
                    companyWiki = {
                        org: org,
                        companyReport: companyReports[0]
                    };
                    console.log('Including company context in employee report generation');
                }
            } catch (error) {
                console.warn('Could not fetch company report for context:', error);
            }

            const data = await secureApi.generateEmployeeReport(employee, submissionAnswers, companyWiki);

            if ((data as any).report) {
                console.log('Employee report generated successfully');
                const report = (data as any).report as EmployeeReport;
                setReports(prev => ({ ...prev, [employee.id]: report }));
                return report;
            } else {
                throw new Error('No report data received from API');
            }
        } catch (e) {
            console.error('generateEmployeeReport error', e);
            throw e; // Re-throw to allow caller to handle
        }
    }, [user?.uid, orgId, submissions, org, getFullCompanyReportHistory]);

    // Memoize the entire context value to prevent unnecessary re-renders
    const value = useMemo(() => ({
        org,
        orgId,
        employees,
        submissions,
        reports,
        loading,
        upsertOrg,
        saveReport,
        inviteEmployee,
        getReportVersions,
        saveReportVersion,
        acceptInvite,
        saveCompanyReport,
        getCompanyReportHistory,
        saveFullCompanyReport,
        getFullCompanyReportHistory,
        generateCompanyReport,
        generateCompanyWiki,
        seedInitialData,
        isOwner,
        issueInviteViaApi,
        getInviteStatus,
        consumeInvite,
        submitEmployeeAnswers,
        generateEmployeeReport,
        getEmployeeReport,
        getEmployeeReports,
    }), [
        org,
        orgId,
        employees,
        submissions,
        reports,
        loading,
        upsertOrg,
        saveReport,
        inviteEmployee,
        getReportVersions,
        saveReportVersion,
        acceptInvite,
        saveCompanyReport,
        getCompanyReportHistory,
        saveFullCompanyReport,
        getFullCompanyReportHistory,
        generateCompanyReport,
        generateCompanyWiki,
        seedInitialData,
        isOwner,
        issueInviteViaApi,
        getInviteStatus,
        consumeInvite,
        submitEmployeeAnswers,
        generateEmployeeReport,
        getEmployeeReport,
        getEmployeeReports,
    ]);

    return (
        <OrgContext.Provider value={value}>
            {children}
        </OrgContext.Provider>
    );
};

export const useOrg = () => {
    const ctx = useContext(OrgContext);
    if (!ctx) throw new Error('useOrg must be used within OrgProvider');
    return ctx;
};
