const express = require('express');

const db = require('../db/models');
const wrapAsync = require('../helpers').wrapAsync;
const ActivitiesDBApi = require('../db/api/activities');

const router = express.Router();
const { QueryTypes } = db.Sequelize;

const RELATION_MODELS = {
  lead: db.leads,
  deal: db.deals,
  contact: db.contacts,
};

const RELATION_LABELS = {
  lead: 'Potansiyel müşteri',
  deal: 'Fırsat',
  contact: 'Kişi',
};

const ACTIVITY_TYPES = new Set([
  'call',
  'email',
  'meeting',
  'task',
  'note',
  'demo',
  'follow_up',
]);

function getOrganizationId(currentUser) {
  return (
    currentUser?.organizations?.id ||
    currentUser?.organization?.id ||
    currentUser?.organizationsId ||
    currentUser?.organizationId ||
    null
  );
}

function buildScopedWhere(alias, globalAccess, organizationId, extraClauses = []) {
  const clauses = [`${alias}."deletedAt" IS NULL`];

  if (!globalAccess && organizationId) {
    clauses.push(`${alias}."organizationsId" = :organizationId`);
  }

  return [...clauses, ...extraClauses].join(' AND ');
}

async function findScopedEntity(model, id, organizationId, globalAccess) {
  const where = { id };

  if (!globalAccess && organizationId) {
    where.organizationsId = organizationId;
  }

  return model.findOne({ where });
}

router.get(
  '/',
  wrapAsync(async (req, res) => {
    const { currentUser } = req;
    const globalAccess = Boolean(currentUser?.app_role?.globalAccess);
    const organizationId = getOrganizationId(currentUser);
    const replacements = {
      userId: currentUser.id,
    };

    if (!globalAccess && organizationId) {
      replacements.organizationId = organizationId;
    }

    const leadScope = buildScopedWhere('l', globalAccess, organizationId, [
      'l."ownerId" = :userId',
      'COALESCE(l.status, \'new\') NOT IN (\'disqualified\', \'converted\')',
    ]);
    const dealScope = buildScopedWhere('d', globalAccess, organizationId, [
      'd."ownerId" = :userId',
      'COALESCE(d.status, \'open\') = \'open\'',
    ]);
    const activityOpenScope = buildScopedWhere('a', globalAccess, organizationId, [
      'a."assigned_toId" = :userId',
      'COALESCE(a.status, \'planned\') NOT IN (\'done\', \'canceled\')',
    ]);
    const activityDoneScope = buildScopedWhere('a', globalAccess, organizationId, [
      'a."assigned_toId" = :userId',
      'COALESCE(a.status, \'planned\') = \'done\'',
    ]);

    const [statsRows, followUps, recentLeads, stageSummary, quickOptions] =
      await Promise.all([
        db.sequelize.query(
          `SELECT
            (SELECT COUNT(*)::int FROM "leads" l WHERE ${leadScope}) AS "myOpenLeads",
            (SELECT COUNT(*)::int FROM "deals" d WHERE ${dealScope}) AS "myActiveDeals",
            (SELECT COUNT(*)::int FROM "activities" a WHERE ${activityOpenScope} AND a."due_at" IS NOT NULL AND DATE(a."due_at") = CURRENT_DATE) AS "dueToday",
            (SELECT COUNT(*)::int FROM "activities" a WHERE ${activityOpenScope} AND a."due_at" IS NOT NULL AND a."due_at" < NOW()) AS "overdue",
            (SELECT COUNT(*)::int FROM "activities" a WHERE ${activityDoneScope} AND a."completed_at" >= NOW() - INTERVAL '7 days') AS "completedThisWeek"`,
          {
            replacements,
            type: QueryTypes.SELECT,
          },
        ),
        db.sequelize.query(
          `SELECT
            a.id,
            a.subject,
            a.status,
            a."activity_type" AS "activityType",
            a."due_at" AS "dueAt",
            COALESCE(d.name, l.title, NULLIF(TRIM(CONCAT(c.first_name, ' ', c.last_name)), ''), c.email, 'Unlinked activity') AS "relatedName",
            CASE
              WHEN a."dealId" IS NOT NULL THEN 'deal'
              WHEN a."leadId" IS NOT NULL THEN 'lead'
              WHEN a."contactId" IS NOT NULL THEN 'contact'
              ELSE 'activity'
            END AS "relatedType",
            COALESCE(a."dealId", a."leadId", a."contactId") AS "relatedId"
          FROM "activities" a
          LEFT JOIN "deals" d ON d.id = a."dealId" AND d."deletedAt" IS NULL
          LEFT JOIN "leads" l ON l.id = a."leadId" AND l."deletedAt" IS NULL
          LEFT JOIN "contacts" c ON c.id = a."contactId" AND c."deletedAt" IS NULL
          WHERE ${activityOpenScope}
          ORDER BY
            CASE WHEN a."due_at" IS NULL THEN 1 ELSE 0 END,
            a."due_at" ASC,
            a."createdAt" DESC
          LIMIT 8`,
          {
            replacements,
            type: QueryTypes.SELECT,
          },
        ),
        db.sequelize.query(
          `SELECT
            l.id,
            l.title,
            l.status,
            l."estimated_value" AS "estimatedValue",
            l."next_follow_up_at" AS "nextFollowUpAt",
            c.name AS "companyName",
            ps.name AS "stageName"
          FROM "leads" l
          LEFT JOIN "companies" c ON c.id = l."companyId" AND c."deletedAt" IS NULL
          LEFT JOIN "pipeline_stages" ps ON ps.id = l."stageId" AND ps."deletedAt" IS NULL
          WHERE ${leadScope}
          ORDER BY l."createdAt" DESC
          LIMIT 6`,
          {
            replacements,
            type: QueryTypes.SELECT,
          },
        ),
        db.sequelize.query(
          `SELECT
            COALESCE(ps.id::text, 'unassigned') AS id,
            COALESCE(ps.name, 'Unassigned') AS name,
            COUNT(d.id)::int AS "dealCount",
            COALESCE(SUM(d.amount), 0)::float AS amount
          FROM "deals" d
          LEFT JOIN "pipeline_stages" ps ON ps.id = d."stageId" AND ps."deletedAt" IS NULL
          WHERE ${dealScope}
          GROUP BY COALESCE(ps.id::text, 'unassigned'), COALESCE(ps.name, 'Unassigned'), COALESCE(ps."sort_order", 999)
          ORDER BY COALESCE(ps."sort_order", 999) ASC, COALESCE(ps.name, 'Unassigned') ASC`,
          {
            replacements,
            type: QueryTypes.SELECT,
          },
        ),
        Promise.all([
          db.sequelize.query(
            `SELECT l.id, l.title AS label
            FROM "leads" l
            WHERE ${leadScope}
            ORDER BY l."updatedAt" DESC
            LIMIT 8`,
            {
              replacements,
              type: QueryTypes.SELECT,
            },
          ),
          db.sequelize.query(
            `SELECT d.id, d.name AS label
            FROM "deals" d
            WHERE ${dealScope}
            ORDER BY d."updatedAt" DESC
            LIMIT 8`,
            {
              replacements,
              type: QueryTypes.SELECT,
            },
          ),
          db.sequelize.query(
            `SELECT c.id, COALESCE(NULLIF(TRIM(CONCAT(c.first_name, ' ', c.last_name)), ''), c.email, 'Untitled contact') AS label
            FROM "contacts" c
            WHERE ${buildScopedWhere('c', globalAccess, organizationId, ['c."ownerId" = :userId'])}
            ORDER BY c."updatedAt" DESC
            LIMIT 8`,
            {
              replacements,
              type: QueryTypes.SELECT,
            },
          ),
        ]),
      ]);

    return res.status(200).json({
      stats: statsRows[0] || {
        myOpenLeads: 0,
        myActiveDeals: 0,
        dueToday: 0,
        overdue: 0,
        completedThisWeek: 0,
      },
      followUps,
      recentLeads,
      stageSummary,
      quickOptions: {
        leads: quickOptions[0],
        deals: quickOptions[1],
        contacts: quickOptions[2],
      },
    });
  }),
);

router.post(
  '/follow-ups',
  wrapAsync(async (req, res) => {
    const { currentUser } = req;
    const globalAccess = Boolean(currentUser?.app_role?.globalAccess);
    const organizationId = getOrganizationId(currentUser);
    const data = req.body?.data || {};
    const subject = typeof data.subject === 'string' ? data.subject.trim() : '';
    const details = typeof data.details === 'string' ? data.details.trim() : '';
    const relationType = data.relationType;
    const relationId = data.relationId;
    const activityType = ACTIVITY_TYPES.has(data.activity_type)
      ? data.activity_type
      : 'follow_up';

    if (!subject) {
      return res.status(400).json({ message: 'Konu alanı zorunludur.' });
    }

    if (!data.due_at) {
      return res.status(400).json({ message: 'Termin tarihi zorunludur.' });
    }

    if (!RELATION_MODELS[relationType] || !relationId) {
      return res.status(400).json({
        message: 'Takibin bağlanacağı bir potansiyel müşteri, fırsat veya kişi seçin.',
      });
    }

    const relationEntity = await findScopedEntity(
      RELATION_MODELS[relationType],
      relationId,
      organizationId,
      globalAccess,
    );

    if (!relationEntity) {
      return res.status(400).json({
        message: `${RELATION_LABELS[relationType]} bulunamadı veya erişilemez durumda.`,
      });
    }

    const transaction = await db.sequelize.transaction();

    try {
      const activity = await ActivitiesDBApi.create(
        {
          activity_type: activityType,
          status: 'planned',
          subject,
          details: details || null,
          due_at: data.due_at,
          assigned_to: currentUser.id,
          organizations: organizationId,
          [relationType]: relationId,
        },
        {
          currentUser,
          transaction,
        },
      );

      await transaction.commit();

      return res.status(200).json({
        id: activity.id,
        subject: activity.subject,
      });
    } catch (error) {
      await transaction.rollback();
      throw error;
    }
  }),
);

module.exports = router;
