const { DataTypes } = require('sequelize');

module.exports = (sequelize) => {
    const TaskEvent = sequelize.define(
        'TaskEvent',
        {
            id: {
                type: DataTypes.INTEGER,
                primaryKey: true,
                autoIncrement: true,
            },
            task_id: {
                type: DataTypes.INTEGER,
                allowNull: false,
                references: {
                    model: 'tasks',
                    key: 'id',
                },
            },
            user_id: {
                type: DataTypes.INTEGER,
                allowNull: false,
                references: {
                    model: 'users',
                    key: 'id',
                },
            },
            event_type: {
                type: DataTypes.STRING,
                allowNull: false,
                validate: {
                    isIn: [
                        [
                            'created',
                            'status_changed',
                            'priority_changed',
                            'due_date_changed',
                            'defer_until_changed',
                            'project_changed',
                            'project_id_changed',
                            'name_changed',
                            'description_changed',
                            'note_changed',
                            'completed',
                            'archived',
                            'deleted',
                            'restored',
                            'today_changed',
                            'tags_changed',
                            'recurrence_changed',
                            'recurrence_type_changed',
                            'recurrence_interval_changed',
                            'recurrence_weekday_changed',
                            'recurrence_month_day_changed',
                            'recurrence_week_of_month_changed',
                            'completion_based_changed',
                            'recurrence_end_date_changed',
                        ],
                    ],
                },
            },
            old_value: {
                type: DataTypes.TEXT,
                allowNull: true,
                get() {
                    const rawValue = this.getDataValue('old_value');
                    return rawValue ? JSON.parse(rawValue) : null;
                },
                set(value) {
                    this.setDataValue(
                        'old_value',
                        value ? JSON.stringify(value) : null
                    );
                },
            },
            new_value: {
                type: DataTypes.TEXT,
                allowNull: true,
                get() {
                    const rawValue = this.getDataValue('new_value');
                    return rawValue ? JSON.parse(rawValue) : null;
                },
                set(value) {
                    this.setDataValue(
                        'new_value',
                        value ? JSON.stringify(value) : null
                    );
                },
            },
            field_name: {
                type: DataTypes.STRING,
                allowNull: true,
                validate: {
                    isIn: [
                        [
                            'status',
                            'priority',
                            'due_date',
                            'defer_until',
                            'project_id',
                            'name',
                            'description',
                            'note',
                            'today',
                            'tags',
                            'recurrence_type',
                            'recurrence_interval',
                            'recurrence_end_date',
                            'recurrence_weekday',
                            'recurrence_month_day',
                            'recurrence_week_of_month',
                            'completion_based',
                        ],
                    ],
                },
            },
            metadata: {
                type: DataTypes.TEXT,
                allowNull: true,
                get() {
                    const rawValue = this.getDataValue('metadata');
                    return rawValue ? JSON.parse(rawValue) : null;
                },
                set(value) {
                    this.setDataValue(
                        'metadata',
                        value ? JSON.stringify(value) : null
                    );
                },
            },
        },
        {
            tableName: 'task_events',
            timestamps: true,
            createdAt: 'created_at',
            updatedAt: false, // We don't need updated_at for events (they're immutable)
            indexes: [
                {
                    fields: ['task_id'],
                },
                {
                    fields: ['user_id'],
                },
                {
                    fields: ['event_type'],
                },
                {
                    fields: ['created_at'],
                },
                {
                    fields: ['task_id', 'event_type'],
                },
                {
                    fields: ['task_id', 'created_at'],
                },
            ],
        }
    );

    // Define associations
    TaskEvent.associate = function (models) {
        // TaskEvent belongs to Task
        TaskEvent.belongsTo(models.Task, {
            foreignKey: 'task_id',
            as: 'Task',
        });

        // TaskEvent belongs to User
        TaskEvent.belongsTo(models.User, {
            foreignKey: 'user_id',
            as: 'User',
        });
    };

    // Helper methods for common event types
    TaskEvent.createStatusChangeEvent = async function (
        taskId,
        userId,
        oldStatus,
        newStatus,
        metadata = {}
    ) {
        return await TaskEvent.create({
            task_id: taskId,
            user_id: userId,
            event_type: 'status_changed',
            field_name: 'status',
            old_value: { status: oldStatus },
            new_value: { status: newStatus },
            metadata: metadata,
        });
    };

    TaskEvent.createTaskCreatedEvent = async function (
        taskId,
        userId,
        taskData,
        metadata = {}
    ) {
        return await TaskEvent.create({
            task_id: taskId,
            user_id: userId,
            event_type: 'created',
            field_name: null,
            old_value: null,
            new_value: taskData,
            metadata: metadata,
        });
    };

    TaskEvent.createFieldChangeEvent = async function (
        taskId,
        userId,
        fieldName,
        oldValue,
        newValue,
        metadata = {}
    ) {
        const eventType =
            fieldName === 'status' && newValue === 2
                ? 'completed'
                : fieldName === 'status' && newValue === 3
                  ? 'archived'
                  : `${fieldName}_changed`;

        return await TaskEvent.create({
            task_id: taskId,
            user_id: userId,
            event_type: eventType,
            field_name: fieldName,
            old_value: { [fieldName]: oldValue },
            new_value: { [fieldName]: newValue },
            metadata: metadata,
        });
    };

    // Query helpers
    TaskEvent.getTaskTimeline = async function (taskId) {
        return await TaskEvent.findAll({
            where: { task_id: taskId },
            order: [['created_at', 'ASC']],
            include: [
                {
                    model: sequelize.models.User,
                    as: 'User',
                    attributes: ['id', 'name', 'email'],
                },
            ],
        });
    };

    TaskEvent.getCompletionTime = async function (taskId) {
        const events = await TaskEvent.findAll({
            where: {
                task_id: taskId,
                event_type: ['status_changed', 'created', 'completed'],
            },
            order: [['created_at', 'ASC']],
        });

        if (events.length === 0) return null;

        const startEvent = events.find(
            (e) =>
                e.event_type === 'created' ||
                (e.event_type === 'status_changed' && e.new_value?.status === 1) // in_progress
        );

        const completedEvent = events.find(
            (e) =>
                e.event_type === 'completed' ||
                (e.event_type === 'status_changed' && e.new_value?.status === 2) // done
        );

        if (!startEvent || !completedEvent) return null;

        const startTime = new Date(startEvent.created_at);
        const endTime = new Date(completedEvent.created_at);

        return {
            started_at: startTime,
            completed_at: endTime,
            duration_ms: endTime - startTime,
            duration_hours: (endTime - startTime) / (1000 * 60 * 60),
        };
    };

    return TaskEvent;
};
