import { Request, Response } from 'express';
import db from '../models';
import { Op } from 'sequelize';
import { PaginationHelper } from '../helpers/paginate';

const WeeklyPlanModel = db.WeeklyPlan;
const UserModel = db.User;
const ClientMasterModel = db.ClientMaster;
const ProjectMasterModel = db.ProjectMaster;
const RoleMasterModel = db.RoleMaster;

export const createWeeklyPlan = async (req: Request, res: Response): Promise<void> => {
  try {
    const {
      id,
      task_name,
      type,
      client_id,
      project_id,
      start_date,
      end_date,
      executive_id,
    } = req.body;

    if (
      !task_name ||
      !type ||
      !client_id ||
      !project_id ||
      !start_date ||
      !end_date
    ) {
      res.status(400).json({
        success: false,
        message: 'Required fields are missing'
      });
      return;
    }

    const user_id = req.user.user_data.id;

    // Validate executive_id (must refer to a User with role_id = 3)
    if (executive_id) {
      const executiveUser = await UserModel.findByPk(executive_id);
    
      if (!executiveUser) {
        res.status(400).json({
          success: false,
          message: 'Executive member not found'
        });
        return;
      }
    
      if (executiveUser.role_id !== 3) {
        res.status(400).json({
          success: false,
          message: 'Only executive members can be assigned'
        });
        return;
      }
    }

    const startDay = new Date(start_date).getDay(); // 1 = Mon
    const endDay = new Date(end_date).getDay();     // 5 = Fri

    if (startDay !== 1 || endDay !== 5) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan must start on Monday and end on Friday'
      });
      return;
    }

    // Simple date check (string comparison works for YYYY-MM-DD)
    if (end_date < start_date) {
      res.status(400).json({
        success: false,
        message: 'End date cannot be before start date'
      });
      return;
    }

    let weeklyPlan;

    //update
    if (id) {
      weeklyPlan = await WeeklyPlanModel.findOne({
        where: {
          id,
          is_active: true
        }
      });

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

      await weeklyPlan.update({
        task_name,
        type,
        user_id,
        client_id,
        project_id,
        start_date,
        end_date,
        executive_id
      });

      res.status(200).json({
        success: true,
        message: 'Weekly plan updated successfully',
        data: weeklyPlan
      });
      return;
    }

    //create
    weeklyPlan = await WeeklyPlanModel.create({
      task_name,
      type,
      user_id,
      client_id,
      project_id,
      start_date,
      end_date,
      status: 'ACTIVE',
      is_active: true,
      executive_id
    });

    res.status(201).json({
      success: true,
      message: 'Weekly plan created successfully',
      data: weeklyPlan
    });

  } catch (error) {
    console.error('Weekly plan save error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while saving weekly plan'
    });
  }
};

export const updateWeeklyPlanStatus = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id, status } = req.body;

    if (!id || !status) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan id and status are required'
      });
      return;
    }

    if (!['ACTIVE', 'COMPLETED'].includes(status)) {
      res.status(400).json({
        success: false,
        message: 'Invalid status value'
      });
      return;
    }

    const weeklyPlan = await WeeklyPlanModel.findOne({
      where: {
        id,
        is_active: true
      }
    });

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

    await weeklyPlan.update({ status });

    res.status(200).json({
      success: true,
      message: 'Weekly plan status updated successfully',
      data: weeklyPlan
    });
  } catch (error) {
    console.error('Weekly plan status update error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while updating weekly plan status'
    });
  }
};

export const getWeeklyPlans = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id, status, start_date, end_date, monday_date, page, per_page } = req.query;

    const whereClause: any = {
      is_active: true
    };

    if (id) {
      whereClause.id = id;
    }

    if (status) {
      whereClause.status = status;
    }

    if (status === 'ACTIVE') {
      const today = new Date();
    
      // find current Monday
      const monday = new Date(today);
      monday.setDate(today.getDate() - ((today.getDay() + 6) % 7));
      monday.setHours(0, 0, 0, 0);
    
      // current Friday
      // const friday = new Date(monday);
      // friday.setDate(monday.getDate() + 4);
      // friday.setHours(23, 59, 59, 999);
    
      whereClause.status = 'ACTIVE';
    
      // ONLY past weeks (exclude current + future)
      whereClause.end_date = {
        [Op.lt]: monday
      };
    }

    //Date filtering
    if (start_date && end_date) {
      const startDay = new Date(start_date as string).getDay();
      const endDay = new Date(end_date as string).getDay();

      if (startDay !== 1 || endDay !== 5) {
        res.status(400).json({
          success: false,
          message: 'Weekly plan must start on Monday and end on Friday'
        });
        return;
      }

      if ((end_date as string) < (start_date as string)) {
        res.status(400).json({
          success: false,
          message: 'end_date cannot be before start_date'
        });
        return;
      }

      // Overlapping range logic
      whereClause.start_date = { [Op.lte]: end_date };
      whereClause.end_date = { [Op.gte]: start_date };
    }

    // Fetch monday date
    else if (monday_date) {
      const monday = new Date(monday_date as string);

      if (monday.getDay() !== 1) {
        res.status(400).json({
          success: false,
          message: 'monday_date must be a Monday'
        });
        return;
      }

      const friday = new Date(monday);
      friday.setDate(monday.getDate() + 4);

      whereClause.start_date = { [Op.lte]: friday };
      whereClause.end_date = { [Op.gte]: monday };
    }

    if (status) {
      const weeklyPlans = await WeeklyPlanModel.findAll({
        where: whereClause,
        include: [
          {
            model: UserModel,
            as: 'user', // creator / owner
            required: false,
            attributes: { exclude: ['createdAt', 'updatedAt', 'token'] },
            include: [
              {
                model: RoleMasterModel,
                as: 'RoleMaster',
                required: false,
              },
            ],
          },
          {
            model: UserModel,
            as: 'executive', // assigned executive
            required: false,
            attributes: { exclude: ['createdAt', 'updatedAt', 'token'] },
            include: [
              {
                model: RoleMasterModel,
                as: 'RoleMaster',
                required: false,
              },
            ],
          },
          {
            model: ClientMasterModel,
            as: 'client',
            required: false,
          },
          {
            model: ProjectMasterModel,
            as: 'project',
            required: false,
          },
        ],
        order: [
          ['start_date', 'DESC'],
          ['id', 'DESC']
        ]
      });

      res.status(200).json({
        success: true,
        data: weeklyPlans
      });
      return;
    }

    const { limit, offset } = PaginationHelper.getPaginationParams(
      page as string | number | undefined,
      per_page as string | number | undefined
    );

    const { rows, count } = await WeeklyPlanModel.findAndCountAll({
      where: whereClause,
      include: [
        {
          model: UserModel,
          as: 'user',
          required: false,
          attributes: { exclude: ['createdAt', 'updatedAt', 'token'] },
          include: [
            {
              model: RoleMasterModel,
              as: 'RoleMaster',
              required: false,
            },
          ],
        },
        {
          model: UserModel,
          as: 'executive',
          required: false,
          attributes: { exclude: ['createdAt', 'updatedAt', 'token'] },
          include: [
            {
              model: RoleMasterModel,
              as: 'RoleMaster',
              required: false,
            },
          ],
        },
        {
          model: ClientMasterModel,
          as: 'client',
          required: false,
        },
        {
          model: ProjectMasterModel,
          as: 'project',
          required: false,
        },
      ],
      order: [
        ['start_date', 'DESC'],
        ['id', 'DESC']
      ],
      limit,
      offset
    });

    const paginatedResult = PaginationHelper.paginate({
      data: rows,
      count,
      per_page: limit,
      page: page as string
    });

    res.status(200).json({
      success: true,
      data: paginatedResult.data,
      pagination: paginatedResult.pagination
    });

  } catch (error) {
    console.error('Weekly plan fetch error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while fetching weekly plans'
    });
  }
};

export const updateWeeklyPlanExecutive = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id, executive_id } = req.body;

    if (!id || !executive_id) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan id and executive_id are required'
      });
      return;
    }

    // Validate executive user
    const executiveUser = await UserModel.findByPk(executive_id);

    if (!executiveUser) {
      res.status(400).json({
        success: false,
        message: 'Executive member not found'
      });
      return;
    }

    if (executiveUser.role_id !== 3) {
      res.status(400).json({
        success: false,
        message: 'Only executive members can be assigned'
      });
      return;
    }

    const weeklyPlan = await WeeklyPlanModel.findOne({
      where: {
        id,
        is_active: true
      }
    });

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

    await weeklyPlan.update({ executive_id });

    res.status(200).json({
      success: true,
      message: 'Executive assigned successfully',
      data: weeklyPlan
    });

  } catch (error) {
    console.error('Weekly plan executive update error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while assigning executive'
    });
  }
};

export const forwardWeeklyPlan = async (req: Request, res: Response): Promise<void> => {
  try {
    const { id, start_date, end_date } = req.body;

    if (!id || !start_date || !end_date) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan id, start_date and end_date are required'
      });
      return;
    }

    const startDate = new Date(start_date);
    const endDate = new Date(end_date);

    // Validate Monday (1) and Friday (5)
    if (startDate.getDay() !== 1 || endDate.getDay() !== 5) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan must start on Monday and end on Friday'
      });
      return;
    }

    // Validate date order
    if (endDate < startDate) {
      res.status(400).json({
        success: false,
        message: 'End date cannot be before start date'
      });
      return;
    }

    //Get current week's Monday (local, zeroed time)
    const today = new Date();
    const currentMonday = new Date(today);
    currentMonday.setHours(0, 0, 0, 0);
    currentMonday.setDate(today.getDate() - ((today.getDay() + 6) % 7));

    //Next week's Monday
    const nextMonday = new Date(currentMonday);
    nextMonday.setDate(currentMonday.getDate() + 7);

    //Block past & current week
    if (startDate < nextMonday) {
      res.status(400).json({
        success: false,
        message: 'Weekly plan can only be forwarded to a future week (not current or past week)'
      });
      return;
    }

    const weeklyPlan = await WeeklyPlanModel.findOne({
      where: {
        id,
        is_active: true,
        status: 'ACTIVE'
      }
    });

    if (!weeklyPlan) {
      res.status(404).json({
        success: false,
        message: 'Only ACTIVE weekly plans can be forwarded'
      });
      return;
    }

    await weeklyPlan.update({
      start_date: startDate,
      end_date: endDate
    });

    res.status(200).json({
      success: true,
      message: 'Weekly plan forwarded successfully',
      data: weeklyPlan
    });

  } catch (error) {
    console.error('Weekly plan forward error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while forwarding weekly plan'
    });
  }
};
  
export const deleteWeeklyPlan = async (req: Request,  res: Response): Promise<void> => {
  try {
    const { id } = req.body;

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

    const weeklyPlan = await WeeklyPlanModel.findOne({
      where: {
        id,
        is_active: true
      }
    });

    if (!weeklyPlan) {
      res.status(404).json({
        success: false,
        message: 'Weekly plan not found or already deleted'
      });
      return;
    }

    await weeklyPlan.update({
      is_active: false
    });

    res.status(200).json({
      success: true,
      message: 'Weekly plan deleted successfully'
    });

  } catch (error) {
    console.error('Weekly plan delete error:', error);
    res.status(500).json({
      success: false,
      message: 'Something went wrong while deleting weekly plan'
    });
  }
};
