import { Response } from 'express';
import { Project } from '../models/Project';
import { Company } from '../models/Company';
import { User } from '../models/User';
import { AuthRequest } from '../middleware/auth.middleware';
import { AuditLog } from '../models/AuditLog';
import { createAlert } from '../services/alertService';
import mongoose from 'mongoose';

export const getProjects = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    // Fetch projects without populate (to avoid ObjectId casting issues with string IDs)
    const projects = await Project.find()
      .sort({ createdAt: -1 })
      .lean();

    // Manually populate companyId and managerId to handle both ObjectId and string IDs
    const populatedProjects = await Promise.all(
      projects.map(async (project: any) => {
        // Populate companyId
        if (project.companyId) {
          let company = null;
          try {
            // Check if companyId is a valid ObjectId
            if (mongoose.Types.ObjectId.isValid(project.companyId)) {
              company = await Company.findById(project.companyId).select('name code').lean();
            } else {
              // companyId is a string (demo data) - try to find by _id using native MongoDB query
              const db = mongoose.connection.db;
              if (!db) throw new Error('Database connection not established');
              const companiesCollection = db.collection('companies');
              company = await companiesCollection.findOne(
                { _id: project.companyId },
                { projection: { name: 1, code: 1 } }
              );
            }
          } catch (e: any) {
            // If company lookup fails, just continue without populating
            console.warn(`[Projects Controller] Could not find company with ID: ${project.companyId}`, e.message);
          }

          if (company) {
            project.companyId = {
              _id: company._id,
              name: company.name,
              code: company.code
            };
          } else {
            // If company not found, keep the original companyId value
            // or set to null/undefined based on your frontend needs
            project.companyId = project.companyId;
          }
        }

        // Populate managerId
        if (project.managerId) {
          let manager = null;
          try {
            // Check if managerId is a valid ObjectId
            if (mongoose.Types.ObjectId.isValid(project.managerId)) {
              manager = await User.findById(project.managerId).select('name email').lean();
            } else {
              // managerId is a string (demo data) - try to find by _id using native MongoDB query
              const db = mongoose.connection.db;
              if (!db) throw new Error('Database connection not established');
              const usersCollection = db.collection('users');
              manager = await usersCollection.findOne(
                { _id: project.managerId },
                { projection: { name: 1, email: 1 } }
              );
            }
          } catch (e: any) {
            // If manager lookup fails, just continue without populating
            console.warn(`[Projects Controller] Could not find manager with ID: ${project.managerId}`, e.message);
          }

          if (manager) {
            project.managerId = {
              _id: manager._id,
              name: manager.name,
              email: manager.email
            };
          } else {
            // If manager not found, keep the original managerId value
            project.managerId = project.managerId;
          }
        }

        return project;
      })
    );

    res.json({
      success: true,
      data: populatedProjects,
    });
  } catch (error: any) {
    console.error('[Projects Controller] Error fetching projects:', error);
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch projects',
    });
  }
};

export const createProject = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const project = await Project.create(req.body);

    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'CREATE',
        targetCollection: 'projects',
        targetId: project._id.toString(),
        details: `Created project: ${project.name}`,
      });
    }

    res.status(201).json({
      success: true,
      data: project,
    });
  } catch (error: any) {
    res.status(400).json({
      success: false,
      message: error.message || 'Failed to create project',
    });
  }
};

export const updateProject = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const updateData: Record<string, unknown> = { ...req.body };

    // Remove _id from update data as it is immutable in MongoDB
    delete updateData._id;
    delete updateData.__v;
    delete updateData.createdAt;

    // Clean up IDs if they were sent as objects from frontend (populated data)
    if (updateData.companyId && typeof updateData.companyId === 'object') {
      updateData.companyId = (updateData.companyId as { _id?: unknown })._id ?? updateData.companyId;
    }
    if (updateData.managerId && typeof updateData.managerId === 'object') {
      updateData.managerId = (updateData.managerId as { _id?: unknown })._id ?? updateData.managerId;
    }

    // Ensure segment is normalized to lowercase and matches enum
    if (updateData.segment && typeof updateData.segment === 'string') {
      const normalizedSegment = updateData.segment.toLowerCase();
      if (normalizedSegment === 'residential' || normalizedSegment === 'commercial') {
        updateData.segment = normalizedSegment;
      } else {
        // Fallback to default if invalid segment provided
        updateData.segment = 'commercial';
      }
    }

    // Explicitly handle segment field from request body
    const segmentFromRequest = req.body.segment || req.body.projectType || req.body.type || req.body.portfolioType;
    if (typeof segmentFromRequest === 'string') {
      const s = segmentFromRequest.toLowerCase();
      if (s.includes('residential')) {
        updateData.segment = 'residential';
      } else if (s.includes('commercial')) {
        updateData.segment = 'commercial';
      }
    }

    // Support both string and ObjectId for lookup
    const query = {
      $or: [
        { _id: id },
        { _id: mongoose.Types.ObjectId.isValid(id) ? new mongoose.Types.ObjectId(id) : null }
      ].filter(f => f._id !== null)
    };


    const project = await Project.findOneAndUpdate(
      query,
      { $set: updateData },
      { new: true, runValidators: true }
    );

    if (!project) {
      res.status(404).json({
        success: false,
        message: 'Project not found',
      });
      return;
    }

    // Create alert if project status changed to decommissioned
    if (project.status === 'decommissioned') {
      await createAlert({
        type: 'System',
        message: `Dự án ${project.name} đã được ngừng hoạt động`,
        severity: 'Warning',
        link: `/projects?projectId=${project._id}`,
      });
    }

    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'UPDATE',
        targetCollection: 'projects',
        targetId: project._id.toString(),
        details: `Updated project: ${project.name}`,
      });
    }

    res.json({
      success: true,
      data: project,
    });
  } catch (error: any) {
    res.status(400).json({
      success: false,
      message: error.message || 'Failed to update project',
    });
  }
};

export const deleteProject = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { id } = req.params;

    // Support both string and ObjectId for lookup
    const query = {
      $or: [
        { _id: id },
        { _id: mongoose.Types.ObjectId.isValid(id) ? new mongoose.Types.ObjectId(id) : null }
      ].filter(f => f._id !== null)
    };

    const project = await Project.findOneAndDelete(query);

    if (!project) {
      res.status(404).json({
        success: false,
        message: 'Project not found',
      });
      return;
    }

    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'DELETE',
        targetCollection: 'projects',
        targetId: id,
        details: `Deleted project: ${project.name}`,
      });
    }

    res.json({
      success: true,
      message: 'Project deleted successfully',
    });
  } catch (error: any) {
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to delete project',
    });
  }
};
