import { DomainError } from "../../shared/errors.ts";
import type { Money } from "../../shared/money.ts";
import { assertSellerMaySell, type KycSubmission } from "../kyc/seller-verification.ts";
import { assertCatalogCombination, type CatalogCapabilities, type DeliveryMode, type ProductKind } from "./catalog.ts";

export type ListingStatus = "draft" | "pending_review" | "active" | "paused" | "sold_out" | "rejected";

export interface Listing {
  readonly id: string;
  readonly sellerId: string;
  readonly kind: ProductKind;
  readonly deliveryMode: DeliveryMode;
  readonly region: string;
  readonly server?: string;
  readonly title: string;
  readonly unitPrice: Money;
  readonly status: ListingStatus;
  readonly version: number;
}

export function createListing(input: Omit<Listing, "status" | "version">, latestKyc: KycSubmission | null, capabilities: CatalogCapabilities): Listing {
  assertSellerMaySell(latestKyc);
  assertCatalogCombination(capabilities, { deliveryMode: input.deliveryMode, region: input.region, ...(input.server ? { server: input.server } : {}) });
  const title = input.title.trim();
  if (title.length < 5 || title.length > 160) throw new DomainError("INVALID_LISTING_TITLE", "Listing title must contain 5 to 160 characters.");
  return { ...input, title, status: "draft", version: 1 };
}

export function submitListing(listing: Listing, actorSellerId: string, latestKyc: KycSubmission | null): Listing {
  assertListingOwner(listing, actorSellerId);
  assertSellerMaySell(latestKyc);
  if (!(["draft", "rejected"] as ListingStatus[]).includes(listing.status)) throw new DomainError("INVALID_LISTING_TRANSITION", "Listing cannot be submitted from its current state.");
  return { ...listing, status: "pending_review", version: listing.version + 1 };
}

export function activateListing(listing: Listing, latestKyc: KycSubmission | null): Listing {
  assertSellerMaySell(latestKyc);
  if (listing.status !== "pending_review" && listing.status !== "paused") throw new DomainError("INVALID_LISTING_TRANSITION", "Listing cannot be activated from its current state.");
  return { ...listing, status: "active", version: listing.version + 1 };
}

export function assertListingOwner(listing: Listing, actorSellerId: string): void {
  if (listing.sellerId !== actorSellerId) throw new DomainError("FORBIDDEN", "Listing does not belong to this seller.");
}
