import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/core/storage/prisma";
import { Prisma } from "@prisma/client";
import { encrypt, decrypt, isEncrypted } from "@/core/crypto";

const NAMESPACE = "password-vault";
const KEY_PREFIX = "vault:";

interface VaultEntryData {
  id: string;
  label: string;
  username: string;
  email: string;
  password: string;
  url: string;
  category: string;
  company: string;
  customFields: { key: string; value: string }[];
  notes: string;
  tags: string[];
  visibility: string;
  createdAt: string;
  updatedAt: string;
}

/** Decrypt the password field in a vault entry */
function decryptEntry(entry: VaultEntryData): VaultEntryData {
  return {
    ...entry,
    password: entry.password ? decrypt(entry.password) : "",
  };
}

/** Encrypt the password field in a vault entry */
function encryptEntry(entry: VaultEntryData): VaultEntryData {
  return {
    ...entry,
    password: entry.password ? encrypt(entry.password) : "",
  };
}

/**
 * GET /api/vault — List all vault entries (passwords decrypted)
 * GET /api/vault?id=xxx — Get single entry (password decrypted)
 */
export async function GET(request: NextRequest) {
  const id = request.nextUrl.searchParams.get("id");

  try {
    if (id) {
      const item = await prisma.keyValueStore.findUnique({
        where: {
          namespace_key: { namespace: NAMESPACE, key: `${KEY_PREFIX}${id}` },
        },
      });
      if (!item || !item.value) {
        return NextResponse.json({ entry: null });
      }
      const entry = decryptEntry(item.value as unknown as VaultEntryData);
      return NextResponse.json({ entry });
    }

    // List all
    const items = await prisma.keyValueStore.findMany({
      where: { namespace: NAMESPACE },
      select: { key: true, value: true },
    });

    const entries: VaultEntryData[] = [];
    for (const item of items) {
      if (item.key.startsWith(KEY_PREFIX) && item.value) {
        try {
          entries.push(decryptEntry(item.value as unknown as VaultEntryData));
        } catch {
          // If decryption fails, return the entry as-is (migration fallback)
          entries.push(item.value as unknown as VaultEntryData);
        }
      }
    }

    return NextResponse.json({ entries });
  } catch (error) {
    console.error("Vault GET error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * POST /api/vault — Create or update a vault entry (password encrypted before storage)
 */
export async function POST(request: NextRequest) {
  try {
    const body = await request.json();
    const entry = body.entry as VaultEntryData;

    if (!entry?.id) {
      return NextResponse.json(
        { error: "Entry with id is required" },
        { status: 400 },
      );
    }

    const encrypted = encryptEntry(entry);
    const key = `${KEY_PREFIX}${entry.id}`;

    await prisma.keyValueStore.upsert({
      where: { namespace_key: { namespace: NAMESPACE, key } },
      update: { value: encrypted as unknown as Prisma.InputJsonValue },
      create: {
        namespace: NAMESPACE,
        key,
        value: encrypted as unknown as Prisma.InputJsonValue,
      },
    });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error("Vault POST error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * DELETE /api/vault?id=xxx — Delete a vault entry
 */
export async function DELETE(request: NextRequest) {
  const id = request.nextUrl.searchParams.get("id");

  if (!id) {
    return NextResponse.json(
      { error: "id parameter is required" },
      { status: 400 },
    );
  }

  try {
    await prisma.keyValueStore
      .delete({
        where: {
          namespace_key: { namespace: NAMESPACE, key: `${KEY_PREFIX}${id}` },
        },
      })
      .catch(() => {
        /* Ignore if not found */
      });

    return NextResponse.json({ success: true });
  } catch (error) {
    console.error("Vault DELETE error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}

/**
 * PATCH /api/vault — Re-encrypt all existing entries (migration endpoint)
 * Call once after setting ENCRYPTION_SECRET to encrypt legacy plaintext passwords.
 */
export async function PATCH() {
  try {
    const items = await prisma.keyValueStore.findMany({
      where: { namespace: NAMESPACE },
      select: { key: true, value: true },
    });

    let migrated = 0;
    for (const item of items) {
      if (!item.key.startsWith(KEY_PREFIX) || !item.value) continue;
      const entry = item.value as unknown as VaultEntryData;

      // Skip if already encrypted
      if (entry.password && isEncrypted(entry.password)) continue;

      const encrypted = encryptEntry(entry);
      await prisma.keyValueStore.update({
        where: { namespace_key: { namespace: NAMESPACE, key: item.key } },
        data: { value: encrypted as unknown as Prisma.InputJsonValue },
      });
      migrated++;
    }

    return NextResponse.json({ success: true, migrated });
  } catch (error) {
    console.error("Vault PATCH (migration) error:", error);
    return NextResponse.json(
      { error: "Internal server error" },
      { status: 500 },
    );
  }
}
