// Listing Service for Marketplace
// Handles CRUD operations for marketplace listings

import {
  Listing,
  ListingStatus,
  CreateListingInput,
  UpdateListingInput,
} from './types';
import { listingStore, generateId } from './store';

export class ListingService {
  /**
   * Create a new listing
   */
  async createListing(
    sellerId: string,
    sellerName: string,
    input: CreateListingInput
  ): Promise<Listing> {
    const listing: Listing = {
      id: generateId(),
      sellerId,
      sellerName,
      plantId: input.plantId,
      title: input.title,
      description: input.description,
      price: input.price,
      currency: input.currency || 'USD',
      quantity: input.quantity,
      category: input.category,
      status: ListingStatus.DRAFT,
      location: input.location,
      tags: input.tags || [],
      images: [],
      viewCount: 0,
      createdAt: new Date(),
      updatedAt: new Date(),
      expiresAt: input.expiresAt,
    };

    return listingStore.create(listing);
  }

  /**
   * Get a listing by ID
   */
  async getListingById(id: string): Promise<Listing | null> {
    const listing = listingStore.getById(id);
    return listing || null;
  }

  /**
   * Get a listing and increment view count
   */
  async viewListing(id: string): Promise<Listing | null> {
    listingStore.incrementViewCount(id);
    return this.getListingById(id);
  }

  /**
   * Get all listings by seller
   */
  async getListingsBySeller(sellerId: string): Promise<Listing[]> {
    return listingStore.getBySellerId(sellerId);
  }

  /**
   * Get all active listings
   */
  async getActiveListings(): Promise<Listing[]> {
    return listingStore.getAll().filter(l => l.status === ListingStatus.ACTIVE);
  }

  /**
   * Update a listing
   */
  async updateListing(
    id: string,
    sellerId: string,
    updates: UpdateListingInput
  ): Promise<Listing | null> {
    const listing = listingStore.getById(id);

    if (!listing) {
      return null;
    }

    // Verify ownership
    if (listing.sellerId !== sellerId) {
      throw new Error('Unauthorized: You do not own this listing');
    }

    const updated = listingStore.update(id, updates);
    return updated || null;
  }

  /**
   * Publish a draft listing (make it active)
   */
  async publishListing(id: string, sellerId: string): Promise<Listing | null> {
    const listing = listingStore.getById(id);

    if (!listing) {
      return null;
    }

    if (listing.sellerId !== sellerId) {
      throw new Error('Unauthorized: You do not own this listing');
    }

    if (listing.status !== ListingStatus.DRAFT) {
      throw new Error('Only draft listings can be published');
    }

    return listingStore.update(id, { status: ListingStatus.ACTIVE }) || null;
  }

  /**
   * Cancel a listing
   */
  async cancelListing(id: string, sellerId: string): Promise<Listing | null> {
    const listing = listingStore.getById(id);

    if (!listing) {
      return null;
    }

    if (listing.sellerId !== sellerId) {
      throw new Error('Unauthorized: You do not own this listing');
    }

    if (listing.status === ListingStatus.SOLD) {
      throw new Error('Cannot cancel a sold listing');
    }

    return listingStore.update(id, { status: ListingStatus.CANCELLED }) || null;
  }

  /**
   * Mark listing as sold
   */
  async markAsSold(id: string, sellerId: string): Promise<Listing | null> {
    const listing = listingStore.getById(id);

    if (!listing) {
      return null;
    }

    if (listing.sellerId !== sellerId) {
      throw new Error('Unauthorized: You do not own this listing');
    }

    return listingStore.update(id, {
      status: ListingStatus.SOLD,
      quantity: 0
    }) || null;
  }

  /**
   * Delete a listing (only drafts or cancelled)
   */
  async deleteListing(id: string, sellerId: string): Promise<boolean> {
    const listing = listingStore.getById(id);

    if (!listing) {
      return false;
    }

    if (listing.sellerId !== sellerId) {
      throw new Error('Unauthorized: You do not own this listing');
    }

    if (listing.status === ListingStatus.ACTIVE || listing.status === ListingStatus.SOLD) {
      throw new Error('Cannot delete active or sold listings. Cancel first.');
    }

    return listingStore.delete(id);
  }

  /**
   * Get listing statistics for a seller
   */
  async getSellerStats(sellerId: string): Promise<{
    totalListings: number;
    activeListings: number;
    soldListings: number;
    totalViews: number;
    averagePrice: number;
  }> {
    const listings = listingStore.getBySellerId(sellerId);

    const activeListings = listings.filter(l => l.status === ListingStatus.ACTIVE);
    const soldListings = listings.filter(l => l.status === ListingStatus.SOLD);

    const totalViews = listings.reduce((sum, l) => sum + l.viewCount, 0);
    const averagePrice = listings.length > 0
      ? listings.reduce((sum, l) => sum + l.price, 0) / listings.length
      : 0;

    return {
      totalListings: listings.length,
      activeListings: activeListings.length,
      soldListings: soldListings.length,
      totalViews,
      averagePrice: Math.round(averagePrice * 100) / 100,
    };
  }

  /**
   * Check and expire old listings
   */
  async expireOldListings(): Promise<number> {
    const now = new Date();
    let expiredCount = 0;

    const activeListings = listingStore.getAll().filter(
      l => l.status === ListingStatus.ACTIVE && l.expiresAt
    );

    for (const listing of activeListings) {
      if (listing.expiresAt && listing.expiresAt < now) {
        listingStore.update(listing.id, { status: ListingStatus.EXPIRED });
        expiredCount++;
      }
    }

    return expiredCount;
  }
}

// Export singleton instance
export const listingService = new ListingService();
