/**
 * Vertical Farm Database Service
 * CRUD operations for vertical farms, zones, and crop batches
 */

import prisma from './prisma';
import type {
  VerticalFarm,
  GrowingZone,
  CropBatch,
  GrowingRecipe,
  FarmStatus,
  ZoneStatus,
  CropBatchStatus,
  Prisma,
} from '@prisma/client';
import type { PaginationOptions, PaginatedResult } from './types';
import { createPaginatedResult } from './types';

// ============================================
// VERTICAL FARM OPERATIONS
// ============================================

// Create a vertical farm
export async function createVerticalFarm(data: {
  name: string;
  ownerId: string;
  latitude: number;
  longitude: number;
  address: string;
  city: string;
  country: string;
  timezone?: string;
  specs: Record<string, unknown>;
  environmentalControl?: Record<string, unknown>;
  irrigationSystem?: Record<string, unknown>;
  lightingSystem?: Record<string, unknown>;
  nutrientSystem?: Record<string, unknown>;
  automationLevel?: 'MANUAL' | 'SEMI_AUTOMATED' | 'FULLY_AUTOMATED';
  automationSystems?: Record<string, unknown>;
}): Promise<VerticalFarm> {
  return prisma.verticalFarm.create({
    data: {
      ...data,
      timezone: data.timezone || 'UTC',
      automationLevel: data.automationLevel || 'MANUAL',
      status: 'OFFLINE',
    },
  });
}

// Get vertical farm by ID
export async function getVerticalFarmById(id: string): Promise<VerticalFarm | null> {
  return prisma.verticalFarm.findUnique({
    where: { id },
  });
}

// Get vertical farm with zones
export async function getVerticalFarmWithZones(id: string) {
  return prisma.verticalFarm.findUnique({
    where: { id },
    include: {
      owner: true,
      zones: true,
      cropBatches: {
        where: { status: { not: 'COMPLETED' } },
      },
    },
  });
}

// Update vertical farm
export async function updateVerticalFarm(
  id: string,
  data: Prisma.VerticalFarmUpdateInput
): Promise<VerticalFarm> {
  return prisma.verticalFarm.update({
    where: { id },
    data,
  });
}

// Update farm status
export async function updateFarmStatus(
  id: string,
  status: FarmStatus
): Promise<VerticalFarm> {
  return prisma.verticalFarm.update({
    where: { id },
    data: { status },
  });
}

// Delete vertical farm
export async function deleteVerticalFarm(id: string): Promise<VerticalFarm> {
  return prisma.verticalFarm.delete({
    where: { id },
  });
}

// Get farms with pagination
export async function getVerticalFarms(
  options: PaginationOptions = {},
  filters?: {
    ownerId?: string;
    status?: FarmStatus;
    city?: string;
    country?: string;
  }
): Promise<PaginatedResult<VerticalFarm>> {
  const page = options.page || 1;
  const limit = options.limit || 20;
  const skip = (page - 1) * limit;

  const where: Prisma.VerticalFarmWhereInput = {};
  if (filters?.ownerId) where.ownerId = filters.ownerId;
  if (filters?.status) where.status = filters.status;
  if (filters?.city) where.city = { contains: filters.city, mode: 'insensitive' };
  if (filters?.country) where.country = { contains: filters.country, mode: 'insensitive' };

  const [farms, total] = await Promise.all([
    prisma.verticalFarm.findMany({
      where,
      skip,
      take: limit,
      orderBy: { createdAt: 'desc' },
      include: {
        owner: true,
        zones: true,
      },
    }),
    prisma.verticalFarm.count({ where }),
  ]);

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

// Get farms by owner
export async function getVerticalFarmsByOwner(ownerId: string): Promise<VerticalFarm[]> {
  return prisma.verticalFarm.findMany({
    where: { ownerId },
    include: { zones: true },
    orderBy: { name: 'asc' },
  });
}

// ============================================
// GROWING ZONE OPERATIONS
// ============================================

// Create a growing zone
export async function createGrowingZone(data: {
  name: string;
  farmId: string;
  level: number;
  areaSqm: number;
  lengthM?: number;
  widthM?: number;
  growingMethod: 'NFT' | 'DWC' | 'EBB_FLOW' | 'AEROPONICS' | 'VERTICAL_TOWERS' | 'RACK_SYSTEM';
  plantPositions: number;
  environmentTargets?: Record<string, unknown>;
}): Promise<GrowingZone> {
  return prisma.growingZone.create({
    data: {
      ...data,
      status: 'EMPTY',
    },
  });
}

// Get growing zone by ID
export async function getGrowingZoneById(id: string): Promise<GrowingZone | null> {
  return prisma.growingZone.findUnique({
    where: { id },
  });
}

// Get growing zone with current batch
export async function getGrowingZoneWithBatch(id: string) {
  return prisma.growingZone.findUnique({
    where: { id },
    include: {
      farm: true,
      cropBatches: {
        where: { status: { not: 'COMPLETED' } },
        take: 1,
      },
    },
  });
}

// Update growing zone
export async function updateGrowingZone(
  id: string,
  data: Prisma.GrowingZoneUpdateInput
): Promise<GrowingZone> {
  return prisma.growingZone.update({
    where: { id },
    data,
  });
}

// Update zone status
export async function updateZoneStatus(
  id: string,
  status: ZoneStatus
): Promise<GrowingZone> {
  return prisma.growingZone.update({
    where: { id },
    data: { status },
  });
}

// Delete growing zone
export async function deleteGrowingZone(id: string): Promise<GrowingZone> {
  return prisma.growingZone.delete({
    where: { id },
  });
}

// Get zones by farm
export async function getGrowingZonesByFarm(farmId: string): Promise<GrowingZone[]> {
  return prisma.growingZone.findMany({
    where: { farmId },
    orderBy: [{ level: 'asc' }, { name: 'asc' }],
  });
}

// Update zone environment readings
export async function updateZoneEnvironment(
  id: string,
  readings: Record<string, unknown>
): Promise<GrowingZone> {
  return prisma.growingZone.update({
    where: { id },
    data: { currentEnvironment: readings },
  });
}

// ============================================
// CROP BATCH OPERATIONS
// ============================================

// Create a crop batch
export async function createCropBatch(data: {
  farmId: string;
  zoneId: string;
  cropType: string;
  variety?: string;
  recipeId?: string;
  seedBatchId?: string;
  plantCount: number;
  plantingDate: Date;
  expectedHarvestDate: Date;
  expectedYieldKg: number;
}): Promise<CropBatch> {
  // Update zone status
  await prisma.growingZone.update({
    where: { id: data.zoneId },
    data: {
      status: 'PLANTED',
      currentCrop: data.cropType,
      plantingDate: data.plantingDate,
      expectedHarvestDate: data.expectedHarvestDate,
    },
  });

  return prisma.cropBatch.create({
    data: {
      ...data,
      currentStage: 'germinating',
      currentDay: 0,
      status: 'GERMINATING',
    },
  });
}

// Get crop batch by ID
export async function getCropBatchById(id: string): Promise<CropBatch | null> {
  return prisma.cropBatch.findUnique({
    where: { id },
  });
}

// Get crop batch with details
export async function getCropBatchWithDetails(id: string) {
  return prisma.cropBatch.findUnique({
    where: { id },
    include: {
      farm: true,
      zone: true,
      recipe: true,
      seedBatch: true,
      plants: true,
      harvestBatches: true,
    },
  });
}

// Update crop batch
export async function updateCropBatch(
  id: string,
  data: Prisma.CropBatchUpdateInput
): Promise<CropBatch> {
  return prisma.cropBatch.update({
    where: { id },
    data,
  });
}

// Update crop batch status
export async function updateCropBatchStatus(
  id: string,
  status: CropBatchStatus,
  extras?: {
    currentStage?: string;
    currentDay?: number;
    healthScore?: number;
    actualHarvestDate?: Date;
    actualYieldKg?: number;
    qualityGrade?: string;
  }
): Promise<CropBatch> {
  const batch = await prisma.cropBatch.update({
    where: { id },
    data: { status, ...extras },
  });

  // Update zone status based on batch status
  if (status === 'COMPLETED' || status === 'FAILED') {
    await prisma.growingZone.update({
      where: { id: batch.zoneId },
      data: {
        status: 'CLEANING',
        currentCrop: null,
        plantingDate: null,
        expectedHarvestDate: null,
      },
    });
  } else if (status === 'HARVESTING') {
    await prisma.growingZone.update({
      where: { id: batch.zoneId },
      data: { status: 'HARVESTING' },
    });
  } else if (status === 'GROWING') {
    await prisma.growingZone.update({
      where: { id: batch.zoneId },
      data: { status: 'GROWING' },
    });
  }

  return batch;
}

// Delete crop batch
export async function deleteCropBatch(id: string): Promise<CropBatch> {
  return prisma.cropBatch.delete({
    where: { id },
  });
}

// Get crop batches with pagination
export async function getCropBatches(
  options: PaginationOptions = {},
  filters?: {
    farmId?: string;
    zoneId?: string;
    status?: CropBatchStatus;
    cropType?: string;
  }
): Promise<PaginatedResult<CropBatch>> {
  const page = options.page || 1;
  const limit = options.limit || 20;
  const skip = (page - 1) * limit;

  const where: Prisma.CropBatchWhereInput = {};
  if (filters?.farmId) where.farmId = filters.farmId;
  if (filters?.zoneId) where.zoneId = filters.zoneId;
  if (filters?.status) where.status = filters.status;
  if (filters?.cropType) where.cropType = { contains: filters.cropType, mode: 'insensitive' };

  const [batches, total] = await Promise.all([
    prisma.cropBatch.findMany({
      where,
      skip,
      take: limit,
      orderBy: { plantingDate: 'desc' },
      include: {
        zone: true,
        recipe: true,
      },
    }),
    prisma.cropBatch.count({ where }),
  ]);

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

// Get active batches by farm
export async function getActiveCropBatchesByFarm(farmId: string): Promise<CropBatch[]> {
  return prisma.cropBatch.findMany({
    where: {
      farmId,
      status: { notIn: ['COMPLETED', 'FAILED'] },
    },
    include: {
      zone: true,
      recipe: true,
    },
    orderBy: { expectedHarvestDate: 'asc' },
  });
}

// Add issue to crop batch
export async function addCropBatchIssue(
  id: string,
  issue: {
    type: string;
    severity: string;
    description: string;
    affectedPlants: number;
  }
) {
  const batch = await prisma.cropBatch.findUnique({
    where: { id },
    select: { issues: true },
  });

  const issues = (batch?.issues as unknown[] || []) as Record<string, unknown>[];
  issues.push({
    id: `issue_${Date.now()}`,
    timestamp: new Date().toISOString(),
    ...issue,
  });

  return prisma.cropBatch.update({
    where: { id },
    data: { issues },
  });
}

// ============================================
// GROWING RECIPE OPERATIONS
// ============================================

// Create a growing recipe
export async function createGrowingRecipe(data: {
  name: string;
  cropType: string;
  variety?: string;
  version?: string;
  stages: Record<string, unknown>[];
  expectedDays: number;
  expectedYieldGrams: number;
  expectedYieldPerSqm?: number;
  requirements?: Record<string, unknown>;
  source?: 'INTERNAL' | 'COMMUNITY' | 'COMMERCIAL';
  author?: string;
}): Promise<GrowingRecipe> {
  return prisma.growingRecipe.create({
    data: {
      ...data,
      version: data.version || '1.0',
      source: data.source || 'INTERNAL',
      timesUsed: 0,
    },
  });
}

// Get growing recipe by ID
export async function getGrowingRecipeById(id: string): Promise<GrowingRecipe | null> {
  return prisma.growingRecipe.findUnique({
    where: { id },
  });
}

// Get recipes by crop type
export async function getGrowingRecipesByCrop(cropType: string): Promise<GrowingRecipe[]> {
  return prisma.growingRecipe.findMany({
    where: { cropType: { contains: cropType, mode: 'insensitive' } },
    orderBy: { rating: 'desc' },
  });
}

// Increment recipe usage
export async function incrementRecipeUsage(id: string): Promise<GrowingRecipe> {
  return prisma.growingRecipe.update({
    where: { id },
    data: { timesUsed: { increment: 1 } },
  });
}

// ============================================
// RESOURCE & ANALYTICS OPERATIONS
// ============================================

// Record resource usage
export async function recordResourceUsage(data: {
  farmId: string;
  periodStart: Date;
  periodEnd: Date;
  electricityKwh: number;
  electricityCostUsd?: number;
  renewablePercent?: number;
  peakDemandKw?: number;
  waterUsageL: number;
  waterCostUsd?: number;
  waterRecycledPercent?: number;
  co2UsedKg?: number;
  co2CostUsd?: number;
  nutrientsUsedL?: number;
  nutrientCostUsd?: number;
}) {
  return prisma.resourceUsage.create({ data });
}

// Get resource usage for farm
export async function getResourceUsage(farmId: string, periodStart: Date, periodEnd: Date) {
  return prisma.resourceUsage.findMany({
    where: {
      farmId,
      periodStart: { gte: periodStart },
      periodEnd: { lte: periodEnd },
    },
    orderBy: { periodStart: 'asc' },
  });
}

// Record farm analytics
export async function recordFarmAnalytics(data: {
  farmId: string;
  period: string;
  totalYieldKg: number;
  yieldPerSqmPerYear?: number;
  cropCyclesCompleted: number;
  averageCyclesDays?: number;
  averageQualityScore?: number;
  gradeAPercent?: number;
  wastagePercent?: number;
  cropSuccessRate?: number;
  spaceUtilization?: number;
  laborHoursPerKg?: number;
  revenueUsd?: number;
  costUsd?: number;
  profitMarginPercent?: number;
  revenuePerSqm?: number;
  carbonFootprintKgPerKg?: number;
  waterUseLPerKg?: number;
  energyUseKwhPerKg?: number;
  topCropsByYield?: Record<string, unknown>[];
  topCropsByRevenue?: Record<string, unknown>[];
  topCropsByEfficiency?: Record<string, unknown>[];
}) {
  return prisma.farmAnalytics.create({ data });
}

// Get farm analytics
export async function getFarmAnalytics(farmId: string, period?: string) {
  const where: Prisma.FarmAnalyticsWhereInput = { farmId };
  if (period) where.period = period;

  return prisma.farmAnalytics.findMany({
    where,
    orderBy: { generatedAt: 'desc' },
    take: period ? 1 : 12,
  });
}
