import type { RequestHandler } from './$types';
import { getDb } from '$lib/server/db';

function isValidYmd(input: string): boolean {
  const m = /^\s*(\d{4})-(\d{2})-(\d{2})\s*$/.exec(input || '');
  if (!m) return false;
  const y = Number(m[1]), mo = Number(m[2]), d = Number(m[3]);
  if (!Number.isFinite(y) || !Number.isFinite(mo) || !Number.isFinite(d)) return false;
  if (mo < 1 || mo > 12 || d < 1 || d > 31) return false;
  const dt = new Date(`${String(y).padStart(4, '0')}-${String(mo).padStart(2, '0')}-${String(d).padStart(2, '0')}T00:00:00Z`);
  // Comprobar que el Date resultante coincide (evita 2025-02-31)
  return dt.getUTCFullYear() === y && (dt.getUTCMonth() + 1) === mo && dt.getUTCDate() === d;
}

export const PATCH: RequestHandler = async (event) => {
  const userId = event.locals.userId ?? null;
  if (!userId) {
    return new Response('Unauthorized', { status: 401 });
  }

  const idStr = event.params.id || '';
  const taskId = parseInt(idStr, 10);
  if (!Number.isFinite(taskId) || taskId <= 0) {
    return new Response('Bad Request', { status: 400 });
  }

  let payload: any = null;
  try {
    payload = await event.request.json();
  } catch {
    return new Response('Bad Request', { status: 400 });
  }

  // Validar que al menos se envíe algún campo editable
  const hasDueField = Object.prototype.hasOwnProperty.call(payload ?? {}, 'due_date');
  const hasDescField = Object.prototype.hasOwnProperty.call(payload ?? {}, 'description');
  if (!hasDueField && !hasDescField) {
    return new Response('Bad Request', { status: 400 });
  }

  // due_date (opcional)
  const due_date_raw = payload?.due_date;
  if (hasDueField && due_date_raw !== null && due_date_raw !== undefined && typeof due_date_raw !== 'string') {
    return new Response('Bad Request', { status: 400 });
  }
  const due_date =
    !hasDueField || due_date_raw == null || String(due_date_raw).trim() === ''
      ? null
      : String(due_date_raw).trim();

  if (hasDueField && due_date !== null && !isValidYmd(due_date)) {
    return new Response(JSON.stringify({ error: 'invalid_due_date' }), {
      status: 400,
      headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
    });
  }

  // description (opcional)
  let description: string | undefined = undefined;
  if (hasDescField) {
    const descRaw = payload?.description;
    if (descRaw !== null && descRaw !== undefined && typeof descRaw !== 'string') {
      return new Response('Bad Request', { status: 400 });
    }
    if (descRaw == null) {
      // No permitimos null en description (columna NOT NULL)
      return new Response(JSON.stringify({ error: 'invalid_description' }), {
        status: 400,
        headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
      });
    }
    const normalized = String(descRaw).replace(/\s+/g, ' ').trim();
    if (normalized.length < 1 || normalized.length > 1000) {
      return new Response(JSON.stringify({ error: 'invalid_description' }), {
        status: 400,
        headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
      });
    }
    description = normalized;
  }

  const db = await getDb();

  // Cargar tarea y validar abierta
  const task = db
    .prepare(
      `SELECT id, description, due_date, group_id, created_by, COALESCE(completed, 0) AS completed, completed_at, display_code
       FROM tasks
       WHERE id = ?`
    )
    .get(taskId) as any;

  if (!task) {
    return new Response(JSON.stringify({ status: 'not_found' }), {
      status: 404,
      headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
    });
  }
  if (Number(task.completed) !== 0 || task.completed_at) {
    return new Response(JSON.stringify({ status: 'completed' }), {
      status: 400,
      headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
    });
  }

  // Gating: grupo permitido + usuario miembro activo (si tiene group_id)
  const groupId: string | null = task.group_id ? String(task.group_id) : null;
  if (groupId) {
    const allowed = db
      .prepare(`SELECT 1 FROM allowed_groups WHERE group_id = ? AND status = 'allowed' LIMIT 1`)
      .get(groupId);
    const active = db
      .prepare(
        `SELECT 1 FROM group_members WHERE group_id = ? AND user_id = ? AND is_active = 1 LIMIT 1`
      )
      .get(groupId, userId);
    const gstatus = db
      .prepare(
        `SELECT 1 FROM groups WHERE id = ? AND COALESCE(active,1)=1 AND COALESCE(archived,0)=0 LIMIT 1`
      )
      .get(groupId);

    if (!allowed || !active || !gstatus) {
      return new Response('Forbidden', { status: 403 });
    }
  } else {
    // Tarea sin grupo: permitir si el usuario está asignado o es el creador
    const isAssigned = db
      .prepare(`SELECT 1 FROM task_assignments WHERE task_id = ? AND user_id = ? LIMIT 1`)
      .get(taskId, userId);
    const isCreator = String(task.created_by || '') === String(userId);

    if (!isAssigned && !isCreator) {
      return new Response('Forbidden', { status: 403 });
    }
  }

  // Aplicar actualización
  if (hasDescField && hasDueField) {
    db.prepare(`UPDATE tasks SET description = ?, due_date = ? WHERE id = ?`).run(description!, due_date, taskId);
  } else if (hasDescField) {
    db.prepare(`UPDATE tasks SET description = ? WHERE id = ?`).run(description!, taskId);
  } else if (hasDueField) {
    db.prepare(`UPDATE tasks SET due_date = ? WHERE id = ?`).run(due_date, taskId);
  }

  const updated = db
    .prepare(`SELECT id, description, due_date, display_code FROM tasks WHERE id = ?`)
    .get(taskId) as any;

  const body = {
    status: 'updated',
    task: {
      id: Number(updated.id),
      description: String(updated.description || ''),
      due_date: updated.due_date ? String(updated.due_date) : null,
      display_code: updated.display_code != null ? Number(updated.display_code) : null
    }
  };

  return new Response(JSON.stringify(body), {
    status: 200,
    headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' }
  });
};
