import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import bcrypt from "bcryptjs";

// Helper: Basic Authentication
async function authenticate(req: NextRequest) {
  const authHeader = req.headers.get("authorization");
  if (!authHeader?.startsWith("Basic ")) return null;
  const decoded = Buffer.from(authHeader.slice(6), "base64").toString();
  const sepIdx = decoded.indexOf(":");
  if (sepIdx === -1) return null;
  const email = decoded.substring(0, sepIdx);
  const password = decoded.substring(sepIdx + 1);

  const user = await prisma.user.findUnique({ where: { email } });
  if (!user) return null;
  const valid = await bcrypt.compare(password, user.passwordHash);
  return valid ? user : null;
}

function taskToVTodo(task: {
  id: string;
  title: string;
  note: string | null;
  completed: boolean;
  completedAt: Date | null;
  dueDate: Date | null;
  priority: number;
  createdAt: Date;
  updatedAt: Date;
}) {
  const now = new Date().toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
  const priorityMap: Record<number, number> = { 0: 0, 1: 9, 2: 5, 3: 1 };
  const vtodo = [
    "BEGIN:VTODO",
    `UID:${task.id}@checkflow`,
    `DTSTAMP:${now}`,
    `CREATED:${task.createdAt.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z"}`,
    `LAST-MODIFIED:${task.updatedAt.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z"}`,
    `SUMMARY:${task.title.replace(/\n/g, "\\n")}`,
    `STATUS:${task.completed ? "COMPLETED" : "NEEDS-ACTION"}`,
    `PRIORITY:${priorityMap[task.priority] ?? 0}`,
  ];
  if (task.note) vtodo.push(`DESCRIPTION:${task.note.replace(/\n/g, "\\n")}`);
  if (task.dueDate) vtodo.push(`DUE:${task.dueDate.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z"}`);
  if (task.completedAt) vtodo.push(`COMPLETED:${task.completedAt.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z"}`);
  vtodo.push("END:VTODO");
  return vtodo.join("\r\n");
}

function parseVTodo(vcardBody: string): Partial<{
  uid: string;
  title: string;
  note: string;
  completed: boolean;
  dueDate: Date | null;
  priority: number;
}> {
  const lines = vcardBody.split(/\r?\n/);
  const result: Partial<{
    uid: string;
    title: string;
    note: string;
    completed: boolean;
    dueDate: Date | null;
    priority: number;
  }> = {};

  for (const line of lines) {
    if (line.startsWith("UID:")) {
      result.uid = line.substring(4).replace(/@checkflow$/, "").trim();
    } else if (line.startsWith("SUMMARY:")) {
      result.title = line.substring(8).replace(/\\n/g, "\n").trim();
    } else if (line.startsWith("DESCRIPTION:")) {
      result.note = line.substring(12).replace(/\\n/g, "\n").trim();
    } else if (line.startsWith("STATUS:")) {
      result.completed = line.substring(7).trim().toUpperCase() === "COMPLETED";
    } else if (line.startsWith("DUE:")) {
      const val = line.substring(4).trim();
      try {
        // Parse basic ISO or iCal timestamp (YYYYMMDDTHHMMSSZ or YYYYMMDD)
        if (val.length === 8) {
          const y = parseInt(val.substring(0, 4), 10);
          const m = parseInt(val.substring(4, 6), 10) - 1;
          const d = parseInt(val.substring(6, 8), 10);
          result.dueDate = new Date(Date.UTC(y, m, d));
        } else {
          result.dueDate = new Date(val);
        }
      } catch {
        // ignore parse error
      }
    } else if (line.startsWith("PRIORITY:")) {
      const p = parseInt(line.substring(9).trim(), 10);
      if (p === 1) result.priority = 3; // High
      else if (p === 5) result.priority = 2; // Medium
      else if (p === 9) result.priority = 1; // Low
      else result.priority = 0;
    }
  }

  return result;
}

// OPTIONS for CORS & CalDAV capability discovery
export async function OPTIONS() {
  return new NextResponse(null, {
    status: 200,
    headers: {
      Allow: "OPTIONS, GET, HEAD, POST, PUT, DELETE, PROPFIND, REPORT",
      DAV: "1, 2, 3, calendar-access, extended-mkcol",
      "MS-Author-Via": "DAV",
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "OPTIONS, GET, HEAD, POST, PUT, DELETE, PROPFIND, REPORT",
      "Access-Control-Allow-Headers": "Authorization, Content-Type, Depth, Prefer, If-Match, If-None-Match",
    },
  });
}

// GET: Direct ICS / VTODO download
export async function GET(req: NextRequest) {
  const user = await authenticate(req);
  if (!user) {
    return new NextResponse("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Basic realm="CheckFlow CalDAV"' },
    });
  }

  const tasks = await prisma.task.findMany({
    where: { userId: user.id, parentId: null },
    orderBy: { sortOrder: "asc" },
  });

  const icsContent = [
    "BEGIN:VCALENDAR",
    "VERSION:2.0",
    "PRODID:-//CheckFlow//CheckFlow//EN",
    "CALSCALE:GREGORIAN",
    "METHOD:PUBLISH",
    ...tasks.map(taskToVTodo),
    "END:VCALENDAR",
  ].join("\r\n");

  return new NextResponse(icsContent, {
    headers: {
      "Content-Type": "text/calendar; charset=utf-8",
      "Content-Disposition": 'attachment; filename="checkflow-tasks.ics"',
      "Cache-Control": "no-cache, no-store, must-revalidate",
    },
  });
}

// PROPFIND: Standard CalDAV Discovery for DAVx5 / Apple Reminders
export async function PROPFIND(req: NextRequest) {
  const user = await authenticate(req);
  if (!user) {
    return new NextResponse("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Basic realm="CheckFlow CalDAV"' },
    });
  }

  const host = req.headers.get("host") || "localhost:3000";
  const protocol = req.headers.get("x-forwarded-proto") || "http";
  const baseUrl = `${protocol}://${host}/api/dav`;
  const principalUrl = `${baseUrl}/principals/${encodeURIComponent(user.email)}`;
  const calendarHome = `${baseUrl}/calendars/${encodeURIComponent(user.email)}/`;
  const tasksUrl = `${calendarHome}tasks/`;

  const xmlResponse = `<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav" xmlns:CS="http://calendarserver.org/ns/">
  <!-- Base Principal & Calendar Home -->
  <D:response>
    <D:href>${baseUrl}/</D:href>
    <D:propstat>
      <D:prop>
        <D:current-user-principal><D:href>${principalUrl}</D:href></D:current-user-principal>
        <D:resourcetype><D:collection/></D:resourcetype>
        <C:calendar-home-set><D:href>${calendarHome}</D:href></C:calendar-home-set>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
  <!-- User Principal -->
  <D:response>
    <D:href>${principalUrl}</D:href>
    <D:propstat>
      <D:prop>
        <D:displayname>${user.name || user.email}</D:displayname>
        <D:resourcetype><D:principal/></D:resourcetype>
        <C:calendar-home-set><D:href>${calendarHome}</D:href></C:calendar-home-set>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
  <!-- Tasks Collection (VTODO) -->
  <D:response>
    <D:href>${tasksUrl}</D:href>
    <D:propstat>
      <D:prop>
        <D:displayname>CheckFlow Tasks</D:displayname>
        <D:resourcetype><D:collection/><C:calendar/></D:resourcetype>
        <C:supported-calendar-component-set>
          <C:comp name="VTODO"/>
        </C:supported-calendar-component-set>
        <CS:getctag>"${Date.now()}"</CS:getctag>
        <D:sync-token>data:sync:${Date.now()}</D:sync-token>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>
</D:multistatus>`;

  return new NextResponse(xmlResponse, {
    status: 207,
    headers: {
      "Content-Type": "application/xml; charset=utf-8",
      DAV: "1, 2, 3, calendar-access",
    },
  });
}

// REPORT: Query calendar items
export async function REPORT(req: NextRequest) {
  const user = await authenticate(req);
  if (!user) {
    return new NextResponse("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Basic realm="CheckFlow CalDAV"' },
    });
  }

  const host = req.headers.get("host") || "localhost:3000";
  const protocol = req.headers.get("x-forwarded-proto") || "http";
  const tasksUrl = `${protocol}://${host}/api/dav/calendars/${encodeURIComponent(user.email)}/tasks/`;

  const tasks = await prisma.task.findMany({
    where: { userId: user.id, parentId: null },
    orderBy: { sortOrder: "asc" },
  });

  const responsesXml = tasks
    .map((task) => {
      const vcal = [
        "BEGIN:VCALENDAR",
        "VERSION:2.0",
        "PRODID:-//CheckFlow//CheckFlow//EN",
        taskToVTodo(task),
        "END:VCALENDAR",
      ].join("\r\n");

      return `  <D:response>
    <D:href>${tasksUrl}${task.id}.ics</D:href>
    <D:propstat>
      <D:prop>
        <D:getetag>"${new Date(task.updatedAt).getTime()}"</D:getetag>
        <C:calendar-data xmlns:C="urn:ietf:params:xml:ns:caldav"><![CDATA[${vcal}]]></C:calendar-data>
      </D:prop>
      <D:status>HTTP/1.1 200 OK</D:status>
    </D:propstat>
  </D:response>`;
    })
    .join("\n");

  const xmlResponse = `<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
${responsesXml}
</D:multistatus>`;

  return new NextResponse(xmlResponse, {
    status: 207,
    headers: {
      "Content-Type": "application/xml; charset=utf-8",
      DAV: "1, 2, 3, calendar-access",
    },
  });
}

// PUT: Create or update task via CalDAV sync
export async function PUT(req: NextRequest) {
  const user = await authenticate(req);
  if (!user) {
    return new NextResponse("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Basic realm="CheckFlow CalDAV"' },
    });
  }

  const body = await req.text();
  const parsed = parseVTodo(body);

  if (!parsed.title && !parsed.uid) {
    return new NextResponse("Bad Request: Missing task data", { status: 400 });
  }

  // Find existing task by UID or create new one in user's default/first list
  let task = null;
  if (parsed.uid) {
    task = await prisma.task.findFirst({
      where: { id: parsed.uid, userId: user.id },
    });
  }

  if (task) {
    // Update existing task
    task = await prisma.task.update({
      where: { id: task.id },
      data: {
        ...(parsed.title !== undefined && { title: parsed.title }),
        ...(parsed.note !== undefined && { note: parsed.note }),
        ...(parsed.completed !== undefined && {
          completed: parsed.completed,
          completedAt: parsed.completed ? new Date() : null,
        }),
        ...(parsed.dueDate !== undefined && { dueDate: parsed.dueDate }),
        ...(parsed.priority !== undefined && { priority: parsed.priority }),
      },
    });
    return new NextResponse(null, {
      status: 204,
      headers: {
        ETag: `"${new Date(task.updatedAt).getTime()}"`,
      },
    });
  } else {
    // Create new task in the user's primary list
    let list = await prisma.list.findFirst({
      where: { userId: user.id },
      orderBy: { createdAt: "asc" },
    });

    if (!list) {
      list = await prisma.list.create({
        data: {
          name: "Inbox",
          userId: user.id,
        },
      });
    }

    const newTask = await prisma.task.create({
      data: {
        ...(parsed.uid && { id: parsed.uid }),
        title: parsed.title || "Untitled Task",
        note: parsed.note || null,
        completed: parsed.completed || false,
        completedAt: parsed.completed ? new Date() : null,
        dueDate: parsed.dueDate || null,
        priority: parsed.priority ?? 0,
        listId: list.id,
        userId: user.id,
      },
    });

    return new NextResponse(null, {
      status: 201,
      headers: {
        ETag: `"${new Date(newTask.updatedAt).getTime()}"`,
      },
    });
  }
}

// DELETE: Remove task via CalDAV sync
export async function DELETE(req: NextRequest) {
  const user = await authenticate(req);
  if (!user) {
    return new NextResponse("Unauthorized", {
      status: 401,
      headers: { "WWW-Authenticate": 'Basic realm="CheckFlow CalDAV"' },
    });
  }

  // Extract ID from path URL
  const pathname = req.nextUrl.pathname;
  const match = pathname.match(/\/([a-zA-Z0-9_-]+)\.ics$/);
  const taskId = match ? match[1] : null;

  if (!taskId) {
    return new NextResponse("Not Found", { status: 404 });
  }

  const task = await prisma.task.findFirst({
    where: { id: taskId, userId: user.id },
  });

  if (!task) {
    return new NextResponse("Not Found", { status: 404 });
  }

  await prisma.task.delete({
    where: { id: task.id },
  });

  return new NextResponse(null, { status: 204 });
}
