import { Response } from 'express';
import { Asset } from '../models/Asset';
import { AuthRequest } from '../middleware/auth.middleware';
import { AuditLog } from '../models/AuditLog';
import { createAssetAlert } from '../services/alertService';
import { syncAssetsForProject } from '../services/assetSyncService';
import { collectKPIForProject } from '../services/kpiCollectorService';
import mongoose from 'mongoose';
import { findProjectByIdOrCode } from '../utils/projectHelper';

export const getAssets = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { projectId } = req.query;
    const filter: any = {};

    if (projectId) {
      // Handle both ObjectId and string ID (demo data)
      if (mongoose.Types.ObjectId.isValid(projectId as string)) {
        // Fix: Query for BOTH the ObjectId and the String version to handle Mixed schema types safely
        filter.projectId = {
          $in: [
            new mongoose.Types.ObjectId(projectId as string),
            projectId as string
          ]
        };
      } else {
        // Use helper function to find project without Mongoose casting errors
        const project = await findProjectByIdOrCode(projectId as string);
        if (!project) {
          res.status(404).json({
            success: false,
            message: `Project with ID or code "${projectId}" not found`,
          });
          return;
        }
        filter.projectId = project._id;
      }
    }

    // Use native MongoDB query if projectId is a string to avoid ObjectId casting
    let assets;
    // Check if filter.projectId is a pure string (not the $in object we just created) and not a valid ObjectId
    const isPureStringId = typeof filter.projectId === 'string' && !mongoose.Types.ObjectId.isValid(filter.projectId);

    if (isPureStringId) {
      const db = mongoose.connection.db;
      if (!db) throw new Error('Database connection not established');
      const assetsCollection = db.collection('assets');
      assets = await assetsCollection.find(filter)
        .sort({ createdAt: -1 })
        .toArray();
    } else {
      assets = await Asset.find(filter)
        .populate('projectId', 'name code')
        .populate('parentAssetId', 'name code')
        .sort({ createdAt: -1 })
        .lean();
    }

    res.json({
      success: true,
      data: assets,
    });
  } catch (error: any) {
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch assets',
    });
  }
};

export const getAssetById = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { id } = req.params;

    const asset = await Asset.findById(id)
      .populate('projectId', 'name code')
      .populate('parentAssetId', 'name code')
      .lean();

    if (!asset) {
      res.status(404).json({
        success: false,
        message: 'Asset not found',
      });
      return;
    }

    res.json({
      success: true,
      data: asset,
    });
  } catch (error: any) {
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to fetch asset',
    });
  }
};

export const createAsset = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const assetData = req.body;
    assetData._id = assetData._id || undefined; // Let MongoDB generate if not provided

    const asset = await Asset.create(assetData);

    // Create alert if asset is faulty
    if (String(asset.status).toLowerCase() === 'faulty') {
      await createAssetAlert(
        asset.name,
        asset.code || asset._id.toString(),
        asset._id.toString(),
        'Tài sản có trạng thái lỗi',
        'Critical'
      );
    }

    // Create alert if warranty is expiring soon
    if (asset.warrantyEndDate) {
      const warrantyEnd = new Date(asset.warrantyEndDate);
      const now = new Date();
      const daysUntilExpiry = Math.ceil((warrantyEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
      
      if (daysUntilExpiry <= 30 && daysUntilExpiry > 0) {
        await createAssetAlert(
          asset.name,
          asset.code || asset._id.toString(),
          asset._id.toString(),
          `Bảo hành sắp hết hạn (Còn ${daysUntilExpiry} ngày)`,
          daysUntilExpiry <= 7 ? 'Critical' : 'Warning'
        );
      }
    }

    // Audit log
    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'CREATE',
        targetCollection: 'assets',
        targetId: asset._id.toString(),
        details: `Created asset: ${asset.name}`,
      });
    }

    res.status(201).json({
      success: true,
      data: asset,
    });
  } catch (error: any) {
    res.status(400).json({
      success: false,
      message: error.message || 'Failed to create asset',
    });
  }
};

export const updateAsset = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { id } = req.params;
    const updateData = { ...req.body, updatedAt: new Date() };

    // 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 asset = await Asset.findOneAndUpdate(
      query,
      updateData,
      { new: true, runValidators: true }
    );

    if (!asset) {
      res.status(404).json({
        success: false,
        message: 'Asset not found',
      });
      return;
    }

    // Create alert if asset status changed to faulty
    if (String(asset.status).toLowerCase() === 'faulty') {
      await createAssetAlert(
        asset.name,
        asset.code || asset._id.toString(),
        asset._id.toString(),
        'Tài sản có trạng thái lỗi',
        'Critical'
      );
    }

    // Create alert if warranty is expiring soon
    if (asset.warrantyEndDate) {
      const warrantyEnd = new Date(asset.warrantyEndDate);
      const now = new Date();
      const daysUntilExpiry = Math.ceil((warrantyEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
      
      if (daysUntilExpiry <= 30 && daysUntilExpiry > 0) {
        await createAssetAlert(
          asset.name,
          asset.code || asset._id.toString(),
          asset._id.toString(),
          `Bảo hành sắp hết hạn (Còn ${daysUntilExpiry} ngày)`,
          daysUntilExpiry <= 7 ? 'Critical' : 'Warning'
        );
      }
    }

    // Create alert if asset status changed to faulty
    if (String(asset.status).toLowerCase() === 'faulty') {
      await createAssetAlert(
        asset.name,
        asset.code || asset._id.toString(),
        asset._id.toString(),
        'Tài sản có trạng thái lỗi',
        'Critical'
      );
    }

    // Create alert if warranty is expiring soon
    if (asset.warrantyEndDate) {
      const warrantyEnd = new Date(asset.warrantyEndDate);
      const now = new Date();
      const daysUntilExpiry = Math.ceil((warrantyEnd.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
      
      if (daysUntilExpiry <= 30 && daysUntilExpiry > 0) {
        await createAssetAlert(
          asset.name,
          asset.code || asset._id.toString(),
          asset._id.toString(),
          `Bảo hành sắp hết hạn (Còn ${daysUntilExpiry} ngày)`,
          daysUntilExpiry <= 7 ? 'Critical' : 'Warning'
        );
      }
    }

    // Audit log
    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'UPDATE',
        targetCollection: 'assets',
        targetId: asset._id.toString(),
        details: `Updated asset: ${asset.name}`,
      });
    }

    res.json({
      success: true,
      data: asset,
    });
  } catch (error: any) {
    res.status(400).json({
      success: false,
      message: error.message || 'Failed to update asset',
    });
  }
};

export const deleteAsset = 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 asset = await Asset.findOneAndDelete(query);

    if (!asset) {
      res.status(404).json({
        success: false,
        message: 'Asset not found',
      });
      return;
    }

    // Audit log
    if (req.user) {
      await AuditLog.create({
        userId: req.user._id,
        action: 'DELETE',
        targetCollection: 'assets',
        targetId: id,
        details: `Deleted asset: ${asset.name}`,
      });
    }

    res.json({
      success: true,
      message: 'Asset deleted successfully',
    });
  } catch (error: any) {
    res.status(500).json({
      success: false,
      message: error.message || 'Failed to delete asset',
    });
  }
};

/**
 * Sync assets for a project from Meteocontrol
 * POST /api/assets/sync/:projectId
 */
export const syncAssets = async (req: AuthRequest, res: Response): Promise<void> => {
  try {
    const { projectId } = req.params;
    const { syncKPI, kpiDays } = req.query; // Optional: syncKPI=true, kpiDays=30

    if (!projectId) {
      res.status(400).json({
        success: false,
        message: 'projectId is required',
      });
      return;
    }

    // console.log(`[Sync API] Manual sync requested for project: ${projectId}, syncKPI: ${syncKPI}, kpiDays: ${kpiDays}`);

    const results: {
      assets: { success: boolean; message: string };
      kpi: { success: boolean; message: string; data?: any };
    } = {
      assets: { success: false, message: '' },
      kpi: { success: false, message: '' },
    };

    // Sync Assets
    try {
      const assetsSuccess = await syncAssetsForProject(projectId);
      results.assets = {
        success: assetsSuccess,
        message: assetsSuccess
          ? 'Assets synced successfully from Meteocontrol'
          : 'Failed to sync assets. Please check project Meteocontrol configuration.',
      };
    } catch (syncError: any) {
      // console.error('[Sync API] Error in syncAssetsForProject:', syncError);
      results.assets = {
        success: false,
        message: syncError.message || 'Failed to sync assets',
      };
    }

    // Sync KPI if requested
    if (String(syncKPI) === 'true') {
      try {
        const numDays = kpiDays ? parseInt(kpiDays as string) : 30; // Default: last 30 days
        const today = new Date();
        today.setHours(0, 0, 0, 0);

        let kpiSuccessCount = 0;
        let kpiFailCount = 0;

        for (let i = 0; i < numDays; i++) {
          const targetDate = new Date(today);
          targetDate.setDate(today.getDate() - i);
          targetDate.setHours(0, 0, 0, 0);

          const success = await collectKPIForProject(projectId, targetDate);
          if (success) {
            kpiSuccessCount++;
          } else {
            kpiFailCount++;
          }

          // Small delay to respect rate limits
          if (i < numDays - 1) {
            await new Promise(resolve => setTimeout(resolve, 1000));
          }
        }

        results.kpi = {
          success: kpiSuccessCount > 0,
          message: `KPI collection completed: ${kpiSuccessCount} success, ${kpiFailCount} failed`,
          data: {
            successCount: kpiSuccessCount,
            failCount: kpiFailCount,
            totalDays: numDays,
          },
        };
      } catch (kpiError: any) {
        // console.error('[Sync API] Error in collectKPIForProject:', kpiError);
        results.kpi = {
          success: false,
          message: kpiError.message || 'Failed to sync KPI',
        };
      }
    }

    // Audit log (don't fail if audit log fails)
    if (req.user) {
      try {
        const details = `Synced from Meteocontrol for project: ${projectId}. Assets: ${results.assets.success ? 'Success' : 'Failed'}. KPI: ${results.kpi.success ? 'Success' : results.kpi.message || 'Not requested'}.`;
        await AuditLog.create({
          userId: req.user._id,
          action: 'SYNC',
          targetCollection: 'assets',
          targetId: projectId,
          details,
        });
      } catch (auditError: any) {
        // console.warn('[Sync API] Failed to create audit log:', auditError.message);
        // Don't fail the request if audit log fails
      }
    }

    // Return combined results
    const overallSuccess = results.assets.success || results.kpi.success;
    const statusCode = overallSuccess ? 200 : 500;

    res.status(statusCode).json({
      success: overallSuccess,
      message: 'Sync completed',
      data: results,
    });
  } catch (error: any) {
    // console.error('[Sync API] Unexpected error:', error);
    // Ensure response is sent
    if (!res.headersSent) {
      res.status(500).json({
        success: false,
        message: error.message || 'Failed to sync',
      });
    }
  }
};
