import type { RequestHandler } from './$types';
import { loadAndCheckTask } from '$lib/server/task-helpers';

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;
}

// ---------------------------------------------------------------------------
// Response helpers
// ---------------------------------------------------------------------------

const badRequest = () => new Response('Bad Request', { status: 400 });
const forbidden = () => new Response('Forbidden', { status: 403 });
const json400 = (error: string) =>
  new Response(JSON.stringify({ error }), {
    status: 400,
    headers: { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' },
  });

// ---------------------------------------------------------------------------
// Validation helpers
// ---------------------------------------------------------------------------

function validateDueDate(raw: unknown): string | null | Response {
  if (raw !== null && raw !== undefined && typeof raw !== 'string') return badRequest();
  const trimmed = raw == null ? null : String(raw).trim();
  if (!trimmed) return null;
  return isValidYmd(trimmed) ? trimmed : json400('invalid_due_date');
}

function validateDescription(raw: unknown): string | Response {
  if (raw !== null && raw !== undefined && typeof raw !== 'string') return badRequest();
  if (raw == null) return json400('invalid_description');
  const normalized = String(raw).replace(/\s+/g, ' ').trim();
  return (normalized.length >= 1 && normalized.length <= 1000)
    ? normalized
    : json400('invalid_description');
}

// ---------------------------------------------------------------------------
// Authorization
// ---------------------------------------------------------------------------

function checkTaskEditAuthorization(db: any, task: any, userId: string): void | Response {
  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 forbidden();
  } else {
    const isAssigned = db
      .prepare(`SELECT 1 FROM task_assignments WHERE task_id = ? AND user_id = ? LIMIT 1`)
      .get(task.id, userId);
    const isCreator = String(task.created_by || '') === String(userId);
    if (!isAssigned && !isCreator) return forbidden();
  }
}

// ---------------------------------------------------------------------------
// DB persistence
// ---------------------------------------------------------------------------

function applyTaskUpdate(
  db: any,
  taskId: number,
  hasDesc: boolean,
  hasDue: boolean,
  description: string | undefined,
  due_date: string | null,
): void {
  if (hasDesc && hasDue) {
    db.prepare(`UPDATE tasks SET description = ?, due_date = ? WHERE id = ?`).run(description!, due_date, taskId);
  } else if (hasDesc) {
    db.prepare(`UPDATE tasks SET description = ? WHERE id = ?`).run(description!, taskId);
  } else if (hasDue) {
    db.prepare(`UPDATE tasks SET due_date = ? WHERE id = ?`).run(due_date, taskId);
  }
}

function buildUpdatedResponse(db: any, taskId: number): Response {
  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' },
  });
}

// ---------------------------------------------------------------------------
// Handler
// ---------------------------------------------------------------------------

export const PATCH: RequestHandler = async (event) => {
  const ctx = await loadAndCheckTask(event);
  if (ctx instanceof Response) return ctx;
  const { db, task, userId } = ctx;

  let payload: any = null;
  try { payload = await event.request.json(); } catch { return badRequest(); }

  const hasDueField = Object.prototype.hasOwnProperty.call(payload ?? {}, 'due_date');
  const hasDescField = Object.prototype.hasOwnProperty.call(payload ?? {}, 'description');
  if (!hasDueField && !hasDescField) return badRequest();

  const due_date = hasDueField ? validateDueDate(payload?.due_date) : null;
  if (due_date instanceof Response) return due_date;

  let description: string | undefined;
  if (hasDescField) {
    const result = validateDescription(payload?.description);
    if (result instanceof Response) return result;
    description = result;
  }

  const auth = checkTaskEditAuthorization(db, task, userId);
  if (auth instanceof Response) return auth;

  applyTaskUpdate(db, task.id, hasDescField, hasDueField, description, due_date as string | null);

  return buildUpdatedResponse(db, task.id);
};
