<?php

namespace App\Services;

use App\Models\Batches;
use App\Models\Farm;
use App\Models\Harvest;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class HarvestService
{
    public function __construct(
        protected AuditTrailService $auditTrail
    ) {}

    public function getAll($status)
    {
        $user = Auth()->user();

        $harvest = Harvest::where("lead_man_id", $user->id)
            ->useFilters()
            ->dynamicPaginate();

        return $harvest;
    }

    public function getById(int $id)
    {
        $user = Auth()->user();

        $harvest = Harvest::with("lines")
            ->where("created_by", $user->id)
            ->find($id);

        return $harvest;
    }

    public function create(array $data)
    {
        $user = Auth()->user();

        $totalHarvest = collect($data['harvest_line'])->sum('total_heads');
        $totalWeight = collect($data['harvest_line'])->sum('total_weight');

        $farm = Farm::findOrFail($data["farm_id"]);
        $batch = Batches::findOrFail($data["batch_id"]);

        $harvest = Harvest::create([
            "harvest_date" => Carbon::parse($data["harvest_date"])->format('Y-m-d'),
            "harvest_time" => Carbon::parse($data["harvest_date"])->format('H:i:s'),
            "buyer_type" => $data["buyer_type"],
            "buyer" => $data["buyer"],
            "plate_no" => $data["plate_no"],

            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],

            "farm_id" => $data["farm_id"],
            "farm_code" => $farm->code,
            "farm_name" => $farm->name,

            "batch_id" => $data["batch_id"],
            "batch_code" => $batch->batch_no,

            "lead_man_id" => $data["farm_leadman_id"],
            "lead_man_name" => $data["farm_leadman_name"],

            "population_before_harvest" => $batch->current_population,
            "remaining" => $batch->current_population - $totalHarvest,

            "total_harvest" => $totalHarvest,
            "total_weight" => $totalWeight,

            "created_by" => $user->id,

            "status" => "draft",
            "synced_status" => $data["synced_status"] ?? "unsynced",
            "synced_at" => $data["synced_at"] ?? NULL,
            "synced_id" => $data["synced_id"] ?? NULL,
        ]);

        foreach ($data['harvest_line'] as $line) {
            $harvest->lines()->create([
                "total_heads" => $line["total_heads"],
                "total_weight" => $line["total_weight"],
            ]);
        }

        $newPopulation = $batch->current_population - $totalHarvest;

        $batch->update([
            "total_harvested" => $batch->total_harvested + $totalHarvest,
            "current_population" => $newPopulation,
            "status" => $newPopulation <= 0 ? "completed" : $batch->status,
        ]);

        Transaction::create([
            "batch_id" => $batch->id,
            "farm_id" => $batch->farm_id,
            "farm_name" => $batch->farm_name,
            "building_id" => $batch->building_id,
            "building_name" => $batch->building_name,
            "transaction_id" => $harvest->id,
            "transaction_type" => "harvest",
            "quantity" => -$harvest->total_harvest,
            "transaction_date" => $harvest->harvest_date,
            "remarks" => "Harvested - Total: {$harvest->total_harvest}",
            "created_by" => auth()->id(),
        ]);

        $this->auditTrail->log(
            __("models.transaction"),
            __("models.harvest"),
            $harvest->id,
            __("models.lc_created"),
            $harvest,
            null,
            $data
        );

        return $harvest->load('lines');
    }

    public function update(int $id, array $data)
    {
        $harvest = Harvest::find($id);

        $batch = Batches::findOrFail($harvest->batch_id);

        $oldTotalHarvest = $harvest->total_harvest;

        $newTotalHarvest = collect($data['harvest_line'])->sum('total_heads');
        $newTotalWeight  = collect($data['harvest_line'])->sum('total_weight');

        $harvestDiff = $newTotalHarvest - $oldTotalHarvest;

        $newPopulation = $batch->current_population - $harvestDiff;

        $harvest->update([
            "population_before_harvest" => $batch->current_population + $oldTotalHarvest,
            "remaining"                 => ($batch->current_population + $oldTotalHarvest) - $newTotalHarvest,
            "total_harvest"             => $newTotalHarvest,
            "total_weight"              => $newTotalWeight,
        ]);

        $incomingIds = [];

        foreach ($data['harvest_line'] as $line) {
            $harvestLine = $harvest->lines()->updateOrCreate(
                ["id" => $line["id"] ?? null],
                [
                    "total_heads"  => $line["total_heads"],
                    "total_weight" => $line["total_weight"],
                ]
            );

            $incomingIds[] = $harvestLine->id;
        }

        $harvest->lines()->whereNotIn('id', $incomingIds)->delete();

        $batch->update([
            "total_harvested"    => $batch->total_harvested + $harvestDiff,
            "current_population" => $newPopulation,
            "status"             => $newPopulation <= 0 ? "completed" : $batch->status,
        ]);

        $this->auditTrail->log(
            __("models.transaction"),
            __("models.harvest"),
            $harvest->id,
            __("models.lc_updated"),
            $harvest,
            null,
            $data
        );

        return $harvest->load('lines');
    }

    public function saveRecords(array $ids, $attachment = null)
    {

        $recordsToSave = Harvest::whereIn("id", $ids)
            ->where("status", "!=", "saved")
            ->get();

        $alreadySavedIds = Harvest::whereIn("id", $ids)
            ->where("status", "=", "saved")
            ->pluck("id")
            ->toArray();

        if ($recordsToSave->isEmpty()) {
            return [
                "harvest" => Harvest::whereIn("id", $ids)->get(),
                "already_saved_ids" => $alreadySavedIds,
            ];
        }

        $idsToSave = $recordsToSave->pluck("id")->toArray();

        $attachmentPath = null;
        if ($attachment) {
            $harvestId = $recordsToSave
                ->pluck("id")
                ->unique()
                ->toArray();

            $attachmentPath = $this->saveAttachmentToBatch(
                $attachment,
                $harvestId
            );
        }

        Harvest::whereIn("id", $idsToSave)->update([
            "status" => __("models.lc_save"),
        ]);

        $harvest = Harvest::whereIn("id", $ids)->get();

        $auditData = [
            "ids" => $idsToSave,
            "status" => __("models.lc_save"),
        ];

        if ($attachmentPath) {
            $auditData["attachment_path"] = $attachmentPath;
        }

        foreach ($recordsToSave as $record) {
            $this->auditTrail->log(
                __("models.transaction"),
                __("models.harvest"),
                $record->id,
                "status_changed_to_saved",
                null,
                null,
                $auditData
            );
        }

        return [
            "harvest" => $harvest,
            "already_saved_ids" => $alreadySavedIds,
        ];
    }

    protected function saveAttachmentToBatch($attachment, array $harvestId)
    {

        try {
            $extension = $attachment->getClientOriginalExtension();
            $filename = Str::random(16) . ".{$extension}";

            $path = $attachment->storeAs(
                "harvesting/attachments",
                $filename,
                "public"
            );

            Harvest::whereIn("id", $harvestId)->update([
                "attachment_path" => $path,
                "attachment_uploaded_at" => Carbon::now()->timeZone("Asia/Manila"),
            ]);


            return $path;
        } catch (\Exception $e) {
            return null;
        }
    }

    public function viewAttachment($harvestId)
    {
        $harvest = Harvest::find($harvestId);

        if (!$harvest) {
            return null;
        }

        if (
            !$harvest->attachment_path ||
            !Storage::disk("public")->exists($harvest->attachment_path)
        ) {
            abort(404, "Attachment not found");
        }

        return Storage::disk("public")->response($harvest->attachment_path);
    }
}
