<?php

namespace App\Services;

use App\Models\Fertilization;
use App\Models\Harvest;
use App\Models\PlannedTask;
use App\Models\Pruning;
use App\Models\Spraying;
use App\Models\Treatment;
use App\Models\VineyardRow;
use App\Models\Watering;
use Carbon\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class BulkPlannedTaskService
{
    /**
     * Create planned tasks for multiple rows at once.
     */
    public function handle(array $payload): array
    {
        $rows = VineyardRow::with('varietyVariation')
            ->whereIn('id', $payload['rows'])
            ->get();

        if ($rows->isEmpty()) {
            return [
                'success' => false,
                'message' => 'No vineyard rows matched the provided selection.',
                'created' => 0,
                'task_ids' => [],
                'errors' => [],
            ];
        }

    $plannedDate = Carbon::parse($payload['planned_date'])->startOfDay();
    $executionDate = isset($payload['execution_date']) ? Carbon::parse($payload['execution_date'])->startOfDay() : null;
    $note = $payload['note'] ?? null;
    $details = $payload['details'] ?? [];
    $action = $payload['action'];

        $createdTasks = collect();
        $errors = [];

        DB::transaction(function () use ($rows, $action, $details, $plannedDate, $executionDate, $note, &$createdTasks, &$errors) {
            foreach ($rows as $row) {
                try {
                    $taskable = $this->createTaskable($action, $row, $details, $note, $plannedDate);

                    $plannedTask = $taskable->plannedTask()->create([
                        'planned_date' => $plannedDate->toDateString(),
                        'execution_date' => $executionDate?->toDateString(),
                        'type' => ucfirst($action),
                        'note' => $note,
                    ]);

                    $createdTasks->push($plannedTask);
                } catch (RuntimeException $exception) {
                    $errors[] = [
                        'row_id' => $row->getKey(),
                        'message' => $exception->getMessage(),
                    ];
                }
            }
        });

        $success = $createdTasks->isNotEmpty() && empty($errors);

        return [
            'success' => $success,
            'message' => $this->buildMessage($createdTasks, $errors, $rows->count()),
            'created_tasks_count' => $createdTasks->count(),
            'task_ids' => $createdTasks->map(fn (PlannedTask $task) => $task->getKey()),
            'errors' => $errors,
        ];
    }

    /**
     * Create the appropriate taskable model for the action.
     */
    protected function createTaskable(string $action, VineyardRow $row, array $details, ?string $note, Carbon $plannedDate)
    {
        return match ($action) {
            'watering' => $this->createWatering($row, $details, $note),
            'fertilization' => $this->createFertilization($row, $details, $note),
            'spraying' => $this->createSpraying($row, $details, $note),
            'pruning' => $this->createPruning($row, $details, $note),
            'harvest' => $this->createHarvest($row, $details, $note, $plannedDate),
            default => throw new RuntimeException("Unsupported planned task action: {$action}"),
        };
    }

    protected function createWatering(VineyardRow $row, array $details, ?string $note): Watering
    {
        $treatment = Treatment::create([
            'row_id' => $row->getKey(),
            'note' => $note,
        ]);

        return Watering::create([
            'treatment_id' => $treatment->getKey(),
            'time_interval' => $details['time_interval'] ?? null,
            'amount' => $details['amount'] ?? null,
            'note' => $note,
        ]);
    }

    protected function createFertilization(VineyardRow $row, array $details, ?string $note): Fertilization
    {
        if (empty($details['substance'])) {
            throw new RuntimeException('Fertilization requires a substance name.');
        }

        $treatment = Treatment::create([
            'row_id' => $row->getKey(),
            'note' => $note,
        ]);

        return Fertilization::create([
            'treatment_id' => $treatment->getKey(),
            'substance' => $details['substance'],
            'concentration' => $details['concentration'] ?? null,
            'note' => $note,
        ]);
    }

    protected function createSpraying(VineyardRow $row, array $details, ?string $note): Spraying
    {
        if (empty($details['pesticide'])) {
            throw new RuntimeException('Spraying requires a pesticide value.');
        }

        $treatment = Treatment::create([
            'row_id' => $row->getKey(),
            'note' => $note,
        ]);

        return Spraying::create([
            'treatment_id' => $treatment->getKey(),
            'pesticide' => $details['pesticide'],
            'concentration' => $details['concentration'] ?? null,
            'note' => $note,
        ]);
    }

    protected function createPruning(VineyardRow $row, array $details, ?string $note): Pruning
    {
        if (empty($details['method'])) {
            throw new RuntimeException('Pruning requires a pruning method.');
        }

        $treatment = Treatment::create([
            'row_id' => $row->getKey(),
            'note' => $note,
        ]);

        return Pruning::create([
            'treatment_id' => $treatment->getKey(),
            'method' => $details['method'],
            'percentage_removed' => $details['percentage_removed'] ?? null,
            'note' => $note,
        ]);
    }

    protected function createHarvest(VineyardRow $row, array $details, ?string $note, Carbon $plannedDate): Harvest
    {
        $variationId = $details['variety_variation_id'] ?? $row->variety_variation_id;

        if (! $variationId) {
            throw new RuntimeException('A variety variation must be defined for harvest planning.');
        }

        return Harvest::create([
            'vineyard_row_id' => $row->getKey(),
            'variety_variation_id' => $variationId,
            'user_id' => $details['user_id'] ?? null,
            'weight' => $details['weight'] ?? 0,
            'sugar_content' => $details['sugar_content'] ?? null,
            'date' => $details['date'] ?? $plannedDate->toDateString(),
            'quality' => $details['quality'] ?? null,
            'grape_condition' => $details['condition'] ?? null,
            'notes' => $note,
            'weather_conditions' => $details['weather'] ?? null,
            'harvest_time' => $details['time'] ?? null,
        ]);
    }

    protected function buildMessage(Collection $createdTasks, array $errors, int $requestedCount): string
    {
        if ($createdTasks->isEmpty()) {
            return $errors ? 'No tasks were created.' : 'Unable to create planned tasks.';
        }

        if (empty($errors) && $createdTasks->count() === $requestedCount) {
            return 'All planned tasks were created successfully.';
        }

        $failed = count($errors);

        return sprintf(
            'Created %d planned tasks%s.',
            $createdTasks->count(),
            $failed > 0 ? sprintf(' (%d rows could not be processed)', $failed) : ''
        );
    }
}
