const Event = require('../models/Event');
const EventParticipants = require('../models/EventParticipants');
const {Op} = require('sequelize');
const moment = require('moment'); // 날짜 포맷팅 라이브러리
const UserEvent = require('../models/UserEvent.js');
const {redisClient, capCheckLuaScript} = require("../datastore/redis");
const UserCrew = require("../models/UserCrew");

// 한 페이지당 기본 아이템 수
const itemsPerPage = 10;

const countKeyPattern = 'event:${eventID}:participant_count';

// 이벤트 목록 조회 (단일 엔드포인트)
exports.getEvents = async (req, res) => {
    console.log('이벤트 목록 조회 컨트롤러 실행'); // 로그 확인용
    try {
        const {sportTypeId, regionID, eventDate, page = 1} = req.query; // 쿼리 파라미터 가져오기
        const offset = (page - 1) * itemsPerPage; // 시작 지점 계산

        const where = {};

        // 쿼리 파라미터 조건 추가
        if (sportTypeId) where.sportTypeId = sportTypeId;
        if (regionID) where.regionID = regionID;
        if (eventDate) where.eventDate = eventDate;

        // 이벤트 데이터 가져오기
        const {rows: events, count: total} = await Event.findAndCountAll({
            where,
            limit: itemsPerPage,
            offset,
        });

        // 응답 데이터 반환
        res.status(200).json({
            events,
            total,          // 조건에 맞는 총 이벤트 개수
            itemsPerPage,   // 페이지당 이벤트 수
        });
    } catch (error) {
        console.error('이벤트 목록 조회 중 오류:', error);
        res.status(500).json({error: '이벤트 목록 조회 중 오류가 발생했습니다.'});
    }
};

// 이벤트 생성 컨트롤러
exports.createEvent = async (req, res) => {
    try {
        const {
            crewID,
            regionID,
            name,
            sportTypeId,
            eventDate,
            capacity,
            feeCondition,
        } = req.body;

        const userID = req.user.userID;

        // TODO: 클라이언트에게 누락된 필드 정보를 명시적으로 전달하지 못하는 패턴입니다.
        // 추후 리팩터링 시 누락된 필드를 클라이언트에 명확히 알려주는 로직으로 개선할 필요가 있습니다.
        if (!regionID || !sportTypeId) {
            return res.status(400).json({error: '필수 필드가 누락되었습니다.'});
        }

        const newEvent = await Event.create({
            crewID,
            regionID,
            name,
            sportTypeId,
            eventDate,
            capacity,
            feeCondition,
            userID,
        });

        res.status(201).json(newEvent);
    } catch (error) {
        console.error('이벤트 생성 중 오류:', error);
        res.status(500).json({error: '이벤트 생성 중 오류가 발생했습니다.'});
    }
};

// 특정 이벤트 조회 컨트롤러
exports.getEventById = async (req, res) => {
    try {
        const {eventID} = req.params;

        // 이벤트 정보 조회
        const event = await Event.findByPk(eventID, {
            attributes: [
                'eventID',
                'regionID',
                'name',
                'sportTypeId',
                'eventDate',
                'capacity',
                'feeCondition',
                'userID',
                'createdDate',
            ],
        });

        if (!event) {
            return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
        }

        // 현재 참여한 인원 수 계산
        const currentMemberCount = redisClient.get(countKeyPattern).then((result) => {
            return parseInt(result, 10);
        }).catch((error) => {
            console.error('이벤트 참여자 수 조회중 오류', error);

            return UserEvent.count({
                where: {eventID: event.eventID},
            });
        });

        // 이벤트 데이터에 현재 참여한 인원 수 추가
        const response = {
            ...event.toJSON(),
            currentMemberCount, // 현재 참여한 인원 수
        };

        res.status(200).json(response);
    } catch (error) {
        console.error('이벤트 조회 중 오류:', error);
        res.status(500).json({error: '이벤트 조회 중 오류가 발생했습니다.'});
    }
};


// 이벤트 수정 컨트롤러
exports.updateEvent = async (req, res) => {
    try {
        const {eventID} = req.params;

        const updateData = req.body;

        const userID = req.user.userID;

        const event = await Event.findByPk(eventID);
        if (!event) {
            return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
        }

        if (event.userID !== userID) {
            return res.status(403).json({error: '이벤트 수정 권한이 없습니다.'});
        }

        await event.update(updateData);

        res.status(200).json({updatedEvent: event});
    } catch (error) {
        console.error('이벤트 수정 중 오류:', error);
        res.status(500).json({error: '이벤트 수정 중 오류가 발생했습니다.'});
    }
};

// 이벤트 삭제 컨트롤러
exports.deleteEvent = async (req, res) => {
    try {
        const {eventID} = req.params;

        const userID = req.user.userID;

        const event = await Event.findByPk(eventID);
        if (!event) {
            return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
        }

        if (event.userID !== userID) {
            return res.status(403).json({error: '이벤트 삭제 권한이 없습니다.'});
        }

        await event.destroy();

        res.status(200).json({message: '이벤트가 성공적으로 삭제되었습니다.'});
    } catch (error) {
        console.error('이벤트 삭제 중 오류:', error);
        res.status(500).json({error: '이벤트 삭제 중 오류가 발생했습니다.'});
    }
};

// 이벤트 참여 컨트롤러
exports.participateEvent = async (req, res) => {
    const {eventID} = req.params;

    const userID = req.user.userID;

    if (!eventID || !userID) {
        return res.status(400).json({error: '필수 데이터가 누락되었습니다.'});
    }

    const event = await Event.findByPk(eventID);
    if (!event) {
        return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
    }

    const existingParticipant = await EventParticipants.findOne({where: {eventID, userID}});
    if (existingParticipant) {
        return res.status(409).json({error: '이미 이벤트에 참여 중입니다.'});
    }

    const capacity = parseInt(event.capacity, 10);

    try {
        const result = await redisClient.sendCommand([
            'EVAL',
            capCheckLuaScript,
            '1',
            countKeyPattern,
            capacity.toString()
        ]);

        // 인원이 초과하지 않은 경우, 참여 진행.
        if (result === 1) {
            const newParticipant = await EventParticipants.create({
                userID,
                eventID,
                participationDate: new Date(),
                status: 'attending',
            });

            res.status(201).json(newParticipant);
        } else {
            return res.status(409).json({error: '이벤트의 최대 참여 인원 수를 초과했습니다.'});
        }
    } catch (error) {
        // 참여 실패시 가입 카운트를 감소시킴.
        await redisClient.decr(countKeyPattern);

        console.error('이벤트 참여 중 오류:', error);

        res.status(500).json({error: '이벤트 참여 중 오류가 발생했습니다.'});
    }
};

// 이벤트 참여 취소 컨트롤러
exports.cancelParticipation = async (req, res) => {
    try {
        const {eventID} = req.params; // URL에서 eventID 가져오기

        const userID = req.user.userID;

        // 필수 데이터 검증
        if (!eventID || !userID) {
            return res.status(400).json({error: '필수 데이터가 누락되었습니다.'});
        }

        // 이벤트 존재 여부 확인
        const event = await Event.findByPk(eventID);
        if (!event) {
            return res.status(404).json({error: '해당 이벤트가 존재하지 않습니다.'});
        }

        // 참여 기록 확인
        const participant = await EventParticipants.findOne({where: {eventID, userID}});
        if (!participant) {
            return res.status(404).json({error: '참여 기록이 존재하지 않습니다.'});
        }

        // 상태 변경 (참여 취소)
        participant.status = 'canceled';
        await participant.save();
        // 참여 인원 카운트 감소
        await redisClient.decr(countKeyPattern);

        res.status(200).json({
            message: '이벤트 참여가 성공적으로 취소되었습니다.',
            participant,
        });
    } catch (error) {
        console.error('이벤트 참여 취소 중 오류:', error);
        res.status(500).json({error: '이벤트 참여 취소 중 오류가 발생했습니다.'});
    }
};