import { NextRequest } from "next/server";
import { connectDB } from "@/lib/db";
import { Product } from "@/models";
import { InventoryLocation } from "@/models/inventory-location.model";
import { successResponse } from "@/lib/api/response";
import {
  handleApiError,
  AuthenticationError,
  AuthorizationError,
  NotFoundError,
  ValidationError,
} from "@/lib/api/errors";
import { auth } from "@/lib/auth";
import { headers } from "next/headers";
import { getSettings } from "@/models/settings.model";
import { rateLimitByUser } from "@/lib/api/rate-limit-middleware";
import { requireApprovedVendorByUserId } from "@/lib/vendor-guard";
import { applyStockChangeAtomic } from "@/lib/inventory";
import { revalidateProductContent } from "@/lib/cache-invalidation";
import { hasVendorPermission } from "@/lib/rbac";
import { VENDOR_PERMISSIONS } from "@/config/permissions.config";
import type { IUser } from "@/types";
import { withApi } from "@/lib/api/handler";
import { fetchVendorInventoryList } from "@/lib/vendor-inventory-list";
import type { BarcodeFormat, BarcodeSource } from "@/lib/barcode/standards";

export const GET = withApi(
  { auth: "user" },
  async ({ request, session }) => {
    const user = session.user as unknown as IUser;
    const canView = await hasVendorPermission(
      user,
      VENDOR_PERMISSIONS.VIEW_PRODUCTS,
    );
    if (!canView) {
      throw new AuthorizationError("You do not have permission to view inventory");
    }

    await rateLimitByUser(
      request,
      session.user.id,
      "vendor:inventory:list",
      "lenient",
      session.user.role,
    );

    const settings = await getSettings();
    if (!settings.multiVendorMode?.enabled) throw new NotFoundError("Vendor");

    const vendor = await requireApprovedVendorByUserId(session.user.id, {
      allowPaymentRequiredSetup: true,
    });

    const list = await fetchVendorInventoryList(
      new URL(request.url).searchParams,
      vendor._id,
    );

    return successResponse({
      items: list.items,
      locations: list.locations,
      pagination: {
        page: list.page,
        limit: list.limit,
        total: list.total,
        totalPages: list.totalPages,
        hasNext: list.page < list.totalPages,
        hasPrev: list.page > 1,
      },
    });

  },
);

export async function PATCH(request: NextRequest) {
  try {
    const session = await auth.api.getSession({ headers: await headers() });
    if (!session) throw new AuthenticationError();

    const user = session.user as unknown as IUser;
    const canEdit = await hasVendorPermission(
      user,
      VENDOR_PERMISSIONS.EDIT_PRODUCTS,
    );
    if (!canEdit) {
      throw new AuthorizationError("You do not have permission to update inventory");
    }

    await rateLimitByUser(
      request,
      session.user.id,
      "vendor:inventory:update",
      "moderate",
      session.user.role,
    );

    const body = await request.json();
    const { updates } = body;

    if (!Array.isArray(updates) || updates.length === 0) {
      throw new ValidationError("Updates array is required");
    }

    await connectDB();
    const settings = await getSettings();
    if (!settings.multiVendorMode?.enabled) throw new NotFoundError("Vendor");

    const vendor = await requireApprovedVendorByUserId(session.user.id, {
      allowPaymentRequiredSetup: true,
    });

    const results: Array<{
      success: boolean;
      productId: string;
      variantId?: string;
      error?: string;
    }> = [];

    for (const update of updates) {
      const { productId, variantId, quantity, locationId, adjustment } = update;

      if (!productId) {
        results.push({ success: false, productId: "", error: "productId is required" });
        continue;
      }

      try {
        // Guarded compare-and-swap update — see applyStockChangeAtomic for why
        // a document save() must never be used for stock changes.
        const outcome = await applyStockChangeAtomic({
          productId: String(productId),
          variantId: variantId ? String(variantId) : undefined,
          locationId: locationId ? String(locationId) : undefined,
          quantity: Number(quantity),
          adjustment: Boolean(adjustment),
          scopeFilter: { vendorId: vendor._id },
        });
        results.push({
          success: outcome.success,
          productId,
          variantId,
          ...(outcome.error ? { error: outcome.error } : {}),
        });
      } catch (err) {
        results.push({
          success: false,
          productId,
          variantId,
          error: err instanceof Error ? err.message : "Unknown error",
        });
      }
    }

    const successCount = results.filter((result) => result.success).length;

    // Refresh storefront product caches so a vendor's manual stock edit reflects
    // immediately (applyStockChangeAtomic does not self-invalidate).
    if (successCount > 0) {
      revalidateProductContent();
    }

    return successResponse({
      results,
      summary: {
        total: results.length,
        success: successCount,
        failed: results.filter((result) => !result.success).length,
      },
    });
  } catch (error) {
    return handleApiError(error);
  }
}
