import { db } from '../config/database.js';
import { companies, companyReminders } from '../db/schema.js';
import { eq, desc, sql, and, lte, gte, isNull, or, inArray } from 'drizzle-orm';
import { NotFoundError, BadRequestError } from '../utils/errors.js';
import { getAccessibleResourceIds } from '../middlewares/auth/resourceAccessMiddleware.js';
import { logCompanyReminderCreated, logCompanyReminderUpdated, logCompanyReminderDeleted } from './audit.service.js';

const ensureCompanyExists = async (companyId) => {
  const [company] = await db
    .select({ id: companies.id, name: companies.name })
    .from(companies)
    .where(eq(companies.id, companyId))
    .limit(1);

  if (!company) {
    throw new NotFoundError('Firma nenájdená');
  }

  return company;
};

export const getReminderById = async (reminderId) => {
  const [reminder] = await db
    .select()
    .from(companyReminders)
    .where(eq(companyReminders.id, reminderId))
    .limit(1);

  if (!reminder) {
    throw new NotFoundError('Reminder nenájdený');
  }

  return reminder;
};

export const getRemindersByCompanyId = async (companyId) => {
  await ensureCompanyExists(companyId);

  const reminders = await db
    .select()
    .from(companyReminders)
    .where(eq(companyReminders.companyId, companyId))
    .orderBy(companyReminders.dueDate, desc(companyReminders.createdAt));

  return reminders;
};

export const createReminder = async (companyId, data, auditContext = null) => {
  await ensureCompanyExists(companyId);

  const description = data.description?.trim();
  if (!description) {
    throw new BadRequestError('Popis pripomienky je povinný');
  }

  const [reminder] = await db
    .insert(companyReminders)
    .values({
      companyId,
      description,
      dueDate: data.dueDate ? new Date(data.dueDate) : null,
      isChecked: data.isChecked ?? false,
    })
    .returning();

  if (auditContext) {
    await logCompanyReminderCreated(auditContext.userId, reminder.id, companyId, data.dueDate, auditContext.ipAddress, auditContext.userAgent);
  }

  return reminder;
};

export const updateReminder = async (companyId, reminderId, data, auditContext = null) => {
  const reminder = await getReminderById(reminderId);

  if (reminder.companyId !== companyId) {
    throw new NotFoundError('Reminder nenájdený');
  }

  const trimmedDescription = data.description !== undefined
    ? data.description.trim()
    : reminder.description;

  if (data.description !== undefined && !trimmedDescription) {
    throw new BadRequestError('Popis pripomienky je povinný');
  }

  const [updatedReminder] = await db
    .update(companyReminders)
    .set({
      description: trimmedDescription,
      dueDate: data.dueDate !== undefined ? (data.dueDate ? new Date(data.dueDate) : null) : reminder.dueDate,
      isChecked: data.isChecked !== undefined ? data.isChecked : reminder.isChecked,
      updatedAt: new Date(),
    })
    .where(eq(companyReminders.id, reminderId))
    .returning();

  if (auditContext) {
    await logCompanyReminderUpdated(auditContext.userId, reminderId, companyId, reminder.dueDate, data.dueDate, auditContext.ipAddress, auditContext.userAgent);
  }

  return updatedReminder;
};

export const deleteReminder = async (companyId, reminderId, auditContext = null) => {
  const reminder = await getReminderById(reminderId);

  if (reminder.companyId !== companyId) {
    throw new NotFoundError('Reminder nenájdený');
  }

  await db.delete(companyReminders).where(eq(companyReminders.id, reminderId));

  if (auditContext) {
    await logCompanyReminderDeleted(auditContext.userId, reminderId, companyId, reminder.dueDate, auditContext.ipAddress, auditContext.userAgent);
  }

  return { success: true, message: 'Reminder bol odstránený' };
};

export const getReminderSummary = async (userId = null, userRole = null) => {
  // Pre membera filtruj len pristupne firmy
  let accessibleCompanyIds = null;
  if (userRole && userRole !== 'admin' && userId) {
    accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
    if (accessibleCompanyIds.length === 0) {
      return { total: 0, active: 0, completed: 0 };
    }
  }

  let query = db
    .select({
      total: sql`COUNT(*)::int`,
      active: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = false)::int`,
      completed: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = true)::int`,
    })
    .from(companyReminders);

  if (accessibleCompanyIds !== null) {
    query = query.where(inArray(companyReminders.companyId, accessibleCompanyIds));
  }

  const [row] = await query;

  return {
    total: row?.total ?? 0,
    active: row?.active ?? 0,
    completed: row?.completed ?? 0,
  };
};

export const getReminderCountsByCompany = async (userId = null, userRole = null) => {
  // Pre membera filtruj len pristupne firmy
  let accessibleCompanyIds = null;
  if (userRole && userRole !== 'admin' && userId) {
    accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
    if (accessibleCompanyIds.length === 0) {
      return [];
    }
  }

  let query = db
    .select({
      companyId: companyReminders.companyId,
      total: sql`COUNT(*)::int`,
      active: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = false)::int`,
      completed: sql`COUNT(*) FILTER (WHERE ${companyReminders.isChecked} = true)::int`,
    })
    .from(companyReminders);

  if (accessibleCompanyIds !== null) {
    query = query.where(inArray(companyReminders.companyId, accessibleCompanyIds));
  }

  const rows = await query
    .groupBy(companyReminders.companyId)
    .orderBy(desc(companyReminders.companyId));

  return rows;
};

/**
 * Get upcoming reminders for dashboard
 * Returns reminders due within the next 5 days that are not checked
 * Includes company name for display
 * For members: returns only reminders from companies they are assigned to
 */
export const getUpcomingReminders = async (userId = null, userRole = null) => {
  // Pre membera filtruj len pristupne firmy
  let accessibleCompanyIds = null;
  if (userRole && userRole !== 'admin' && userId) {
    accessibleCompanyIds = await getAccessibleResourceIds('company', userId);
    if (accessibleCompanyIds.length === 0) {
      return [];
    }
  }

  const now = new Date();
  const fiveDaysFromNow = new Date();
  fiveDaysFromNow.setDate(fiveDaysFromNow.getDate() + 5);

  const conditions = [
    eq(companyReminders.isChecked, false),
    lte(companyReminders.dueDate, fiveDaysFromNow),
    gte(companyReminders.dueDate, now)
  ];

  if (accessibleCompanyIds !== null) {
    conditions.push(inArray(companyReminders.companyId, accessibleCompanyIds));
  }

  const reminders = await db
    .select({
      id: companyReminders.id,
      description: companyReminders.description,
      dueDate: companyReminders.dueDate,
      isChecked: companyReminders.isChecked,
      companyId: companyReminders.companyId,
      companyName: companies.name,
      createdAt: companyReminders.createdAt,
    })
    .from(companyReminders)
    .leftJoin(companies, eq(companyReminders.companyId, companies.id))
    .where(and(...conditions))
    .orderBy(companyReminders.dueDate);

  return reminders;
};
