
import { Request, Response } from 'express';
import { Contract } from '../models/Contract';
import { findProjectByIdOrCode } from '../utils/projectHelper';
import { createContractExpiryAlert } from '../services/alertService';
import mongoose from 'mongoose';

export const getContracts = async (req: Request, res: Response) => {
    try {
        const { projectId } = req.query;

        if (!projectId) {
            return res.status(400).json({ success: false, message: 'projectId is required' });
        }

        // Handle both ObjectId and string ID
        let projectObjectId: any;

        // Check if projectId is a valid MongoDB ObjectId
        if (mongoose.Types.ObjectId.isValid(projectId as string)) {
            projectObjectId = new mongoose.Types.ObjectId(projectId as string);
        } else {
            // Use helper function to find project without Mongoose casting errors
            const project = await findProjectByIdOrCode(projectId as string);
            if (!project) {
                return res.status(404).json({ success: false, message: `Project with ID or code "${projectId}" not found` });
            }
            projectObjectId = project._id;
        }

        let contracts;

        const queryConditions: any[] = [{ projectId: projectObjectId }];

        // If projectObjectId is a real ObjectId, also look for its string representation
        if (projectObjectId instanceof mongoose.Types.ObjectId) {
            queryConditions.push({ projectId: projectObjectId.toString() });
        }

        contracts = await Contract.find({ $or: queryConditions }).sort({ createdAt: -1 });

        res.json({
            success: true,
            data: contracts
        });
    } catch (error: any) {
        res.status(500).json({ success: false, message: error.message });
    }
};

export const createContract = async (req: Request, res: Response) => {
    try {
        const contractData = req.body;

        // If no _id provided, generate one or let Mongoose handle it (depending on schema)
        // Since schema has _id: String and _id: false in options, we should probably provide one if missing
        if (!contractData._id) {
            contractData._id = new mongoose.Types.ObjectId().toString();
        }

        const newContract = new Contract(contractData);
        await newContract.save();

        // Create alert if contract is expiring soon
        if (newContract.endDate) {
            const endDate = new Date(newContract.endDate);
            const now = new Date();
            const daysUntilExpiry = Math.ceil((endDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
            
            if (daysUntilExpiry <= 30) {
                await createContractExpiryAlert(
                    newContract.contractNumber,
                    newContract._id.toString(),
                    daysUntilExpiry
                );
            }
        }

        res.status(201).json({
            success: true,
            data: newContract
        });
    } catch (error: any) {
        res.status(500).json({ success: false, message: error.message });
    }
};

export const updateContract = async (req: Request, res: Response) => {
    try {
        const { id } = req.params;
        const updateData = { ...req.body };

        // Remove _id from update data as it is immutable in MongoDB
        delete updateData._id;

        // 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 updatedContract = await Contract.findOneAndUpdate(query, updateData, { new: true });

        if (!updatedContract) {
            return res.status(404).json({ success: false, message: 'Contract not found' });
        }

        // Create alert if contract is expiring soon
        if (updatedContract.endDate) {
            const endDate = new Date(updatedContract.endDate);
            const now = new Date();
            const daysUntilExpiry = Math.ceil((endDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
            
            if (daysUntilExpiry <= 30) {
                await createContractExpiryAlert(
                    updatedContract.contractNumber,
                    updatedContract._id.toString(),
                    daysUntilExpiry
                );
            }
        }

        res.json({
            success: true,
            data: updatedContract
        });
    } catch (error: any) {
        res.status(500).json({ success: false, message: error.message });
    }
};

export const deleteContract = async (req: Request, res: Response) => {
    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 deletedContract = await Contract.findOneAndDelete(query);

        if (!deletedContract) {
            return res.status(404).json({ success: false, message: 'Contract not found' });
        }

        res.json({
            success: true,
            message: 'Contract deleted successfully'
        });
    } catch (error: any) {
        res.status(500).json({ success: false, message: error.message });
    }
};
