import { ClubTask, User, UserClub } from '../models/index.js';
import { getSafeErrorMessage } from '../utils/errorUtils.js';
import clubTaskAutomationService from '../services/clubTaskAutomationService.js';
import clubWorkflowSourceService from '../services/clubWorkflowSourceService.js';

const TERMINAL_TASK_STATUSES = new Set(['done', 'cancelled', 'archived']);

function isMissingTaskTableError(error) {
  return error?.original?.code === 'ER_NO_SUCH_TABLE'
    && /club_tasks/.test(String(error?.original?.sqlMessage || ''));
}

function isMissingTaskSuppressionTableError(error) {
  return error?.original?.code === 'ER_NO_SUCH_TABLE'
    && /club_task_suppressions/.test(String(error?.original?.sqlMessage || ''));
}

function normalizeTaskPayload(payload = {}) {
  return {
    title: String(payload.title || '').trim(),
    taskType: payload.taskType?.trim() || null,
    description: payload.description?.trim() || null,
    status: payload.status || 'open',
    priority: payload.priority || 'normal',
    dueAt: payload.dueAt || null,
    remindAt: payload.remindAt || null,
    assignedUserId: payload.assignedUserId ? Number(payload.assignedUserId) : null,
    automationSource: payload.automationSource?.trim() || null,
    automationKey: payload.automationKey?.trim() || null,
    relatedEntityType: payload.relatedEntityType?.trim() || null,
    relatedEntityId: payload.relatedEntityId ? Number(payload.relatedEntityId) : null,
    sourceSnapshot: payload.sourceSnapshot || null,
  };
}

async function loadAssignableUsers(clubId) {
  const entries = await UserClub.findAll({
    where: { clubId },
    include: [{ model: User, as: 'user', attributes: ['id', 'email'] }],
    order: [[{ model: User, as: 'user' }, 'email', 'ASC']],
  });

  return entries
    .filter((entry) => entry.user)
    .filter((entry) => entry.approved || entry.isOwner)
    .map((entry) => ({
      userId: entry.userId,
      email: entry.user.email,
      isOwner: Boolean(entry.isOwner),
      approved: Boolean(entry.approved),
    }));
}

async function validateAssignedUser(clubId, assignedUserId) {
  if (!assignedUserId) {
    return null;
  }

  const userClub = await UserClub.findOne({
    where: {
      clubId,
      userId: assignedUserId,
    },
  });

  if (!userClub || (!userClub.approved && !userClub.isOwner)) {
    const error = new Error('Der zugewiesene Benutzer gehört nicht zu diesem Verein.');
    error.statusCode = 400;
    throw error;
  }

  return assignedUserId;
}

async function loadTaskOrThrow(clubId, taskId) {
  const task = await ClubTask.findOne({
    where: {
      id: taskId,
      clubId,
    },
  });

  if (!task) {
    const error = new Error('Aufgabe wurde nicht gefunden.');
    error.statusCode = 404;
    throw error;
  }

  return task;
}

export const listClubTasks = async (req, res) => {
  try {
    const { clubId } = req.params;
    let tasks = [];
    let automationOverview = { definitions: [], suggestions: [] };

    try {
      [tasks, automationOverview] = await Promise.all([
        ClubTask.findAll({
          where: { clubId },
          include: [{ model: User, as: 'assignedUser', attributes: ['id', 'email'], required: false }],
          order: [
            ['status', 'ASC'],
            ['dueAt', 'ASC'],
            ['updatedAt', 'DESC'],
          ],
        }),
        clubTaskAutomationService.buildAutomationOverview(clubId),
      ]);
    } catch (error) {
      if (!isMissingTaskTableError(error)) {
        throw error;
      }
    }

    const assignableUsers = await loadAssignableUsers(clubId);

    res.status(200).json({
      tasks,
      taskDefinitions: automationOverview.definitions,
      workflowSources: automationOverview.workflowSources || [],
      taskSuggestions: automationOverview.suggestions,
      assignableUsers,
    });
  } catch (error) {
    console.error('[listClubTasks] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Aufgaben konnten nicht geladen werden.'),
    });
  }
};

export const createClubTask = async (req, res) => {
  try {
    const { clubId } = req.params;
    const payload = normalizeTaskPayload(req.body);

    if (!payload.title) {
      return res.status(400).json({ error: 'Titel ist erforderlich.' });
    }

    payload.assignedUserId = await validateAssignedUser(clubId, payload.assignedUserId);

    const task = await ClubTask.create({
      clubId,
      ...payload,
      createdByUserId: req.user?.id || null,
    });

    res.status(201).json({ task });
  } catch (error) {
    console.error('[createClubTask] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Aufgabe konnte nicht gespeichert werden.'),
    });
  }
};

export const updateClubTask = async (req, res) => {
  try {
    const { clubId, taskId } = req.params;
    const task = await loadTaskOrThrow(clubId, taskId);
    const payload = normalizeTaskPayload(req.body);
    const wasDoneBefore = task.status === 'done';

    if (!payload.title) {
      return res.status(400).json({ error: 'Titel ist erforderlich.' });
    }

    payload.assignedUserId = await validateAssignedUser(clubId, payload.assignedUserId);

    await task.update({
      ...payload,
      completedAt: TERMINAL_TASK_STATUSES.has(payload.status) ? (task.completedAt || new Date()) : null,
      archivedAt: payload.status === 'archived' ? (task.archivedAt || new Date()) : null,
    });

    const followUpTasks = !wasDoneBefore && payload.status === 'done'
      ? await clubTaskAutomationService.materializeWorkflowFollowUps(task, req.user?.id || null)
      : [];
    const sourceUpdate = !wasDoneBefore && payload.status === 'done'
      ? await clubWorkflowSourceService.syncSourceStateForCompletedTask(task)
      : null;

    res.status(200).json({ task, followUpTasks, sourceUpdate });
  } catch (error) {
    console.error('[updateClubTask] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Aufgabe konnte nicht gespeichert werden.'),
    });
  }
};

export const updateClubTaskStatus = async (req, res) => {
  try {
    const { clubId, taskId } = req.params;
    const { status } = req.body || {};
    if (!status) {
      return res.status(400).json({ error: 'Status fehlt.' });
    }

    const task = await loadTaskOrThrow(clubId, taskId);
    const wasDoneBefore = task.status === 'done';
    await task.update({
      status,
      completedAt: TERMINAL_TASK_STATUSES.has(status) ? (task.completedAt || new Date()) : null,
      archivedAt: status === 'archived' ? (task.archivedAt || new Date()) : null,
    });
    const followUpTasks = !wasDoneBefore && status === 'done'
      ? await clubTaskAutomationService.materializeWorkflowFollowUps(task, req.user?.id || null)
      : [];
    const sourceUpdate = !wasDoneBefore && status === 'done'
      ? await clubWorkflowSourceService.syncSourceStateForCompletedTask(task)
      : null;
    res.status(200).json({ task, followUpTasks, sourceUpdate });
  } catch (error) {
    console.error('[updateClubTaskStatus] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Status konnte nicht gespeichert werden.'),
    });
  }
};

export const materializeAutomatedClubTasks = async (req, res) => {
  try {
    const { clubId } = req.params;
    const automationKeys = Array.isArray(req.body?.automationKeys) ? req.body.automationKeys : [];

    if (automationKeys.length === 0) {
      return res.status(400).json({ error: 'Es wurden keine Automatik-Schlüssel übergeben.' });
    }

    const tasks = await clubTaskAutomationService.materializeSuggestions(clubId, req.user?.id || null, automationKeys);
    res.status(201).json({ tasks });
  } catch (error) {
    console.error('[materializeAutomatedClubTasks] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Automatische Aufgaben konnten nicht erstellt werden.'),
    });
  }
};

export const dismissAutomatedClubTaskSuggestion = async (req, res) => {
  try {
    const { clubId } = req.params;
    const payload = req.body || {};
    const suppression = await clubTaskAutomationService.dismissSuggestion(clubId, req.user?.id || null, payload);
    res.status(200).json({ success: true, suppression });
  } catch (error) {
    console.error('[dismissAutomatedClubTaskSuggestion] - Error:', error);
    if (isMissingTaskSuppressionTableError(error)) {
      return res.status(500).json({
        error: 'Die Tabelle club_task_suppressions fehlt noch. Bitte die aktuelle SQL-Datei auf dem System ausführen.',
      });
    }
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Vorschlag konnte nicht ausgeblendet werden.'),
    });
  }
};

export const deleteClubTask = async (req, res) => {
  try {
    const { clubId, taskId } = req.params;
    const task = await loadTaskOrThrow(clubId, taskId);
    await task.destroy();
    res.status(200).json({ success: true });
  } catch (error) {
    console.error('[deleteClubTask] - Error:', error);
    res.status(error.statusCode || 500).json({
      error: getSafeErrorMessage(error, 'Aufgabe konnte nicht gelöscht werden.'),
    });
  }
};
