/**
 * Transport Event Database Service
 * CRUD operations for transport events and supply chain tracking
 */

import prisma from './prisma';
import type {
  TransportEvent,
  TransportEventType,
  TransportMethod,
  TransportStatus,
  Prisma,
} from '@prisma/client';
import type { PaginationOptions, PaginatedResult, DateRangeFilter } from './types';
import { createPaginatedResult, calculateDistanceKm } from './types';

// Carbon emission factors (kg CO2 per km per kg of cargo)
const CARBON_FACTORS: Record<TransportMethod, number> = {
  WALKING: 0,
  BICYCLE: 0,
  ELECTRIC_VEHICLE: 0.02,
  HYBRID_VEHICLE: 0.08,
  GASOLINE_VEHICLE: 0.12,
  DIESEL_TRUCK: 0.15,
  ELECTRIC_TRUCK: 0.03,
  REFRIGERATED_TRUCK: 0.25,
  RAIL: 0.01,
  SHIP: 0.008,
  AIR: 0.5,
  DRONE: 0.01,
  LOCAL_DELIVERY: 0.05,
  CUSTOMER_PICKUP: 0.1,
};

// Create a transport event
export async function createTransportEvent(data: {
  eventType: TransportEventType;
  fromLatitude: number;
  fromLongitude: number;
  fromAddress?: string;
  fromCity?: string;
  fromCountry?: string;
  fromLocationType: 'FARM' | 'GREENHOUSE' | 'VERTICAL_FARM' | 'WAREHOUSE' | 'HUB' | 'MARKET' | 'CONSUMER' | 'SEED_BANK' | 'OTHER';
  fromFacilityId?: string;
  fromFacilityName?: string;
  toLatitude: number;
  toLongitude: number;
  toAddress?: string;
  toCity?: string;
  toCountry?: string;
  toLocationType: 'FARM' | 'GREENHOUSE' | 'VERTICAL_FARM' | 'WAREHOUSE' | 'HUB' | 'MARKET' | 'CONSUMER' | 'SEED_BANK' | 'OTHER';
  toFacilityId?: string;
  toFacilityName?: string;
  durationMinutes: number;
  transportMethod: TransportMethod;
  senderId: string;
  receiverId: string;
  notes?: string;
  photos?: string[];
  documents?: string[];
  eventData?: Record<string, unknown>;
  plantIds?: string[];
  seedBatchId?: string;
  harvestBatchId?: string;
  cargoWeightKg?: number;
}): Promise<TransportEvent> {
  // Calculate distance
  const distanceKm = calculateDistanceKm(
    data.fromLatitude,
    data.fromLongitude,
    data.toLatitude,
    data.toLongitude
  );

  // Calculate carbon footprint
  const cargoWeight = data.cargoWeightKg || 1;
  const carbonFootprintKg = distanceKm * CARBON_FACTORS[data.transportMethod] * cargoWeight;

  return prisma.transportEvent.create({
    data: {
      eventType: data.eventType,
      fromLatitude: data.fromLatitude,
      fromLongitude: data.fromLongitude,
      fromAddress: data.fromAddress,
      fromCity: data.fromCity,
      fromCountry: data.fromCountry,
      fromLocationType: data.fromLocationType,
      fromFacilityId: data.fromFacilityId,
      fromFacilityName: data.fromFacilityName,
      toLatitude: data.toLatitude,
      toLongitude: data.toLongitude,
      toAddress: data.toAddress,
      toCity: data.toCity,
      toCountry: data.toCountry,
      toLocationType: data.toLocationType,
      toFacilityId: data.toFacilityId,
      toFacilityName: data.toFacilityName,
      distanceKm,
      durationMinutes: data.durationMinutes,
      transportMethod: data.transportMethod,
      carbonFootprintKg,
      senderId: data.senderId,
      receiverId: data.receiverId,
      status: 'PENDING',
      notes: data.notes,
      photos: data.photos || [],
      documents: data.documents || [],
      eventData: data.eventData,
      seedBatchId: data.seedBatchId,
      harvestBatchId: data.harvestBatchId,
      plants: data.plantIds ? { connect: data.plantIds.map(id => ({ id })) } : undefined,
    },
  });
}

// Get transport event by ID
export async function getTransportEventById(id: string): Promise<TransportEvent | null> {
  return prisma.transportEvent.findUnique({
    where: { id },
  });
}

// Get transport event with related data
export async function getTransportEventWithDetails(id: string) {
  return prisma.transportEvent.findUnique({
    where: { id },
    include: {
      sender: true,
      receiver: true,
      plants: true,
      seedBatch: true,
      harvestBatch: true,
    },
  });
}

// Update transport event
export async function updateTransportEvent(
  id: string,
  data: Prisma.TransportEventUpdateInput
): Promise<TransportEvent> {
  return prisma.transportEvent.update({
    where: { id },
    data,
  });
}

// Update transport event status
export async function updateTransportEventStatus(
  id: string,
  status: TransportStatus,
  signature?: { type: 'sender' | 'receiver' | 'verifier'; signature: string }
): Promise<TransportEvent> {
  const updateData: Prisma.TransportEventUpdateInput = { status };

  if (signature) {
    if (signature.type === 'sender') updateData.senderSignature = signature.signature;
    if (signature.type === 'receiver') updateData.receiverSignature = signature.signature;
    if (signature.type === 'verifier') updateData.verifierSignature = signature.signature;
  }

  return prisma.transportEvent.update({
    where: { id },
    data: updateData,
  });
}

// Delete transport event
export async function deleteTransportEvent(id: string): Promise<TransportEvent> {
  return prisma.transportEvent.delete({
    where: { id },
  });
}

// Get transport events with pagination
export async function getTransportEvents(
  options: PaginationOptions = {},
  filters?: {
    eventType?: TransportEventType;
    senderId?: string;
    receiverId?: string;
    status?: TransportStatus;
    dateRange?: DateRangeFilter;
  }
): Promise<PaginatedResult<TransportEvent>> {
  const page = options.page || 1;
  const limit = options.limit || 20;
  const skip = (page - 1) * limit;

  const where: Prisma.TransportEventWhereInput = {};
  if (filters?.eventType) where.eventType = filters.eventType;
  if (filters?.senderId) where.senderId = filters.senderId;
  if (filters?.receiverId) where.receiverId = filters.receiverId;
  if (filters?.status) where.status = filters.status;
  if (filters?.dateRange) {
    where.timestamp = {
      gte: filters.dateRange.start,
      lte: filters.dateRange.end,
    };
  }

  const [events, total] = await Promise.all([
    prisma.transportEvent.findMany({
      where,
      skip,
      take: limit,
      orderBy: { timestamp: 'desc' },
      include: {
        sender: true,
        receiver: true,
      },
    }),
    prisma.transportEvent.count({ where }),
  ]);

  return createPaginatedResult(events, total, page, limit);
}

// Get transport events by plant
export async function getTransportEventsByPlant(plantId: string): Promise<TransportEvent[]> {
  return prisma.transportEvent.findMany({
    where: {
      plants: {
        some: { id: plantId },
      },
    },
    orderBy: { timestamp: 'asc' },
    include: {
      sender: true,
      receiver: true,
    },
  });
}

// Get plant journey (complete transport history)
export async function getPlantJourney(plantId: string) {
  const plant = await prisma.plant.findUnique({
    where: { id: plantId },
    include: { owner: true },
  });

  if (!plant) return null;

  const events = await prisma.transportEvent.findMany({
    where: {
      plants: {
        some: { id: plantId },
      },
    },
    orderBy: { timestamp: 'asc' },
    include: {
      sender: true,
      receiver: true,
    },
  });

  // Calculate totals
  const totalFoodMiles = events.reduce((sum, e) => sum + e.distanceKm, 0);
  const totalCarbonKg = events.reduce((sum, e) => sum + e.carbonFootprintKg, 0);
  const daysInTransit = events.reduce((sum, e) => sum + e.durationMinutes / 1440, 0);

  return {
    plantId,
    plant,
    events,
    totalFoodMiles,
    totalCarbonKg,
    daysInTransit,
    generation: plant.generation,
  };
}

// Get environmental impact summary
export async function getEnvironmentalImpact(filters?: {
  userId?: string;
  dateRange?: DateRangeFilter;
}) {
  const where: Prisma.TransportEventWhereInput = {};
  if (filters?.userId) {
    where.OR = [
      { senderId: filters.userId },
      { receiverId: filters.userId },
    ];
  }
  if (filters?.dateRange) {
    where.timestamp = {
      gte: filters.dateRange.start,
      lte: filters.dateRange.end,
    };
  }

  const events = await prisma.transportEvent.findMany({ where });

  const totalCarbonKg = events.reduce((sum, e) => sum + e.carbonFootprintKg, 0);
  const totalFoodMiles = events.reduce((sum, e) => sum + e.distanceKm, 0);

  // Breakdown by method
  const breakdownByMethod: Record<string, { distance: number; carbon: number }> = {};
  events.forEach(e => {
    if (!breakdownByMethod[e.transportMethod]) {
      breakdownByMethod[e.transportMethod] = { distance: 0, carbon: 0 };
    }
    breakdownByMethod[e.transportMethod].distance += e.distanceKm;
    breakdownByMethod[e.transportMethod].carbon += e.carbonFootprintKg;
  });

  // Breakdown by event type
  const breakdownByEventType: Record<string, { count: number; carbon: number }> = {};
  events.forEach(e => {
    if (!breakdownByEventType[e.eventType]) {
      breakdownByEventType[e.eventType] = { count: 0, carbon: 0 };
    }
    breakdownByEventType[e.eventType].count += 1;
    breakdownByEventType[e.eventType].carbon += e.carbonFootprintKg;
  });

  return {
    totalCarbonKg,
    totalFoodMiles,
    eventCount: events.length,
    breakdownByMethod,
    breakdownByEventType,
  };
}

// Get user's carbon footprint
export async function getUserCarbonFootprint(userId: string) {
  const events = await prisma.transportEvent.findMany({
    where: {
      OR: [
        { senderId: userId },
        { receiverId: userId },
      ],
    },
  });

  const sent = events.filter(e => e.senderId === userId);
  const received = events.filter(e => e.receiverId === userId);

  return {
    totalCarbonKg: events.reduce((sum, e) => sum + e.carbonFootprintKg, 0),
    totalDistanceKm: events.reduce((sum, e) => sum + e.distanceKm, 0),
    sentEvents: sent.length,
    receivedEvents: received.length,
    sentCarbonKg: sent.reduce((sum, e) => sum + e.carbonFootprintKg, 0),
    receivedCarbonKg: received.reduce((sum, e) => sum + e.carbonFootprintKg, 0),
  };
}

// Seed Batch operations
export async function createSeedBatch(data: {
  species: string;
  variety?: string;
  quantity: number;
  quantityUnit?: string;
  generation?: number;
  germinationRate?: number;
  purityPercentage?: number;
  harvestDate?: Date;
  expirationDate?: Date;
  certifications?: string[];
}) {
  return prisma.seedBatch.create({
    data: {
      ...data,
      quantityUnit: data.quantityUnit || 'seeds',
      generation: data.generation || 0,
      status: 'AVAILABLE',
    },
  });
}

export async function getSeedBatchById(id: string) {
  return prisma.seedBatch.findUnique({
    where: { id },
  });
}

// Harvest Batch operations
export async function createHarvestBatch(data: {
  produceType: string;
  harvestType?: string;
  grossWeight: number;
  netWeight: number;
  weightUnit?: string;
  itemCount?: number;
  qualityGrade?: string;
  qualityNotes?: string;
  packagingType?: string;
  shelfLifeHours?: number;
  cropBatchId?: string;
}) {
  return prisma.harvestBatch.create({
    data: {
      ...data,
      harvestType: data.harvestType || 'full',
      weightUnit: data.weightUnit || 'kg',
    },
  });
}

export async function getHarvestBatchById(id: string) {
  return prisma.harvestBatch.findUnique({
    where: { id },
    include: {
      transportEvents: true,
      cropBatch: true,
    },
  });
}
