<?php

namespace App\Services;

use App\Models\Batches;
use App\Models\ChickenLoadingHeaders;
use App\Models\ChickenLoadingLine;
use App\Models\Transaction;
use App\Models\User;
use App\Services\GenerateBatchNumberService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class LoadingService
{
    public function __construct(
        protected GenerateBatchNumberService $generateBatch,
        protected AuditTrailService $auditTrail
    ) {}

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

        $loadings = ChickenLoadingHeaders::with("batch", "loadingLines")
            ->where("lead_man_id", $user->id)
            ->useFilters()
            ->dynamicPaginate();

        return $loadings;
    }

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

        $loadings = ChickenLoadingHeaders::with("loadingLines")
            ->where("lead_man_id", $user->id)
            ->find($id);

        return $loadings;
    }

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

        $batchData = $this->generateBatch->generateNextBatchNo($data);

        $batch = Batches::create([
            "farm_id" => $data["farm_id"],
            "farm_name" => $data["farm_name"],
            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],
            "batch_no" => $batchData["batch_no"],
            "batch_sequence" => $batchData["batch_sequence"],
            "start_date" => $data["loading_date"],
            "status" => "active",
            "synced_status" => $data["synced_status"] ?? "unsynced",
            "synced_at" => $data["synced_at"] ?? NULL,
            "synced_id" => $data["synced_id"] ?? NULL,
            "initial_population" => $data["total_initial"],
            "current_population" => $data["total_net"],
        ]);

        $header = ChickenLoadingHeaders::create([
            "loading_date" => $data["loading_date"],
            "farm_id" => $data["farm_id"],
            "farm_name" => $data["farm_name"],
            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],
            "batch_id" => $batch->id,
            "batch_no" => $batch->batch_no,
            "loading_date" => $data["loading_date"],
            "lead_man_id" => $user,
            "caretaker_id" => $data["caretaker_id"],
            "total_initial" => $data["total_initial"],
            "total_reject" => $data["total_reject"],
            "total_doa" => $data["total_doa"],
            "total_net" => $data["total_net"],
            "sample_count" => $data["sample_count"],
            "status" => "draft",
            "synced_status" => $data["synced_status"] ?? "unsynced",
            "synced_at" => $data["synced_at"] ?? NULL,
            "synced_id" => $data["synced_id"] ?? NULL,
        ]);

        foreach ($data["lines"] as $line) {
            ChickenLoadingLine::create([
                "header_id" => $header->id,
                "breeder_id" => $line["breeder_id"],
                "breeder_name" => $line["breeder_name"],
                "class_id" => $line["class_id"],
                "class_name" => $line["class_name"],
                "initial_population" => $line["initial_population"],
                "reject" => $line["reject"],
                "doa" => $line["doa"],
                "loaded_at" => $line["loaded_at"],
            ]);
        }

        Transaction::create([
            "batch_id" => $batch->id,
            "farm_id" => $data["farm_id"],
            "farm_name" => $data["farm_name"],
            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],
            "transaction_id" => $header->id,
            "transaction_type" => "chick_loading",
            "quantity" => $data["total_net"],
            "transaction_date" => $data["loading_date"],
            "remarks" => "Initial chick loading for batch {$batch->batch_no}",
            "created_by" => $user,
        ]);

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

        return $header;
    }

    public function update(array $data, $id)
    {
        $user = auth()->id();

        $header = ChickenLoadingHeaders::with(["batch", "loadingLines"])->find(
            $id
        );
        $batch = $header->batch;

        $originalData = [
            "batch" => $batch->toArray(),
            "header" => $header->toArray(),
            "lines" => $header->loadingLines->toArray(),
        ];

        $batch->update([
            "farm_id" => $data["farm_id"],
            "farm_name" => $data["farm_name"],
            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],
            "start_date" => $data["loading_date"],
            "initial_population" => $data["total_net"],
            "current_population" => $data["total_net"],
        ]);

        $header->update([
            "loading_date" => $data["loading_date"],
            "farm_id" => $data["farm_id"],
            "farm_name" => $data["farm_name"],
            "building_id" => $data["building_id"],
            "building_name" => $data["building_name"],
            "caretaker_id" => $data["caretaker_id"],
            "total_initial" => $data["total_initial"],
            "total_reject" => $data["total_reject"],
            "total_doa" => $data["total_doa"],
            "total_net" => $data["total_net"],
            "sample_count" => $data["sample_count"],
        ]);

        $lineIds = [];

        foreach ($data["lines"] as $line) {
            $loadingLine = ChickenLoadingLine::updateOrCreate(
                [
                    "header_id" => $header->id,
                    "id" => $line["id"] ?? null,
                ],
                [
                    "breeder_id" => $line["breeder_id"],
                    "breeder_name" => $line["breeder_name"],
                    "class_id" => $line["class_id"],
                    "class_name" => $line["class_name"],
                    "initial_population" => $line["initial_population"],
                    "reject" => $line["reject"],
                    "doa" => $line["doa"],
                    "loaded_at" => $line["loaded_at"],
                ]
            );

            $lineIds[] = $loadingLine->id;
        }

        $header
            ->loadingLines()
            ->whereNotIn("id", $lineIds)
            ->delete();

        $transaction = Transaction::where("transaction_id", $header->id)
            ->where("transaction_type", "chick_loading")
            ->first();

        if ($transaction) {
            $transaction->update([
                "farm_id" => $data["farm_id"],
                "farm_name" => $data["farm_name"],
                "building_id" => $data["building_id"],
                "building_name" => $data["building_name"],
                "quantity" => $data["total_net"],
                "transaction_date" => $data["loading_date"],
                "remarks" => "Initial chick loading for batch {$batch->batch_no}",
            ]);
        }

        $this->auditTrail->log(
            __("models.transaction"),
            __("models.loading"),
            $header->id,
            __("models.lc_updated"),
            $header->fresh(["loadingLines"]),
            $originalData,
            $data
        );

        return $header->load("loadingLines");
    }

    public function saveRecords(array $ids, $attachment = null)
    {
        // \Log::info("=== saveRecords START ===", [
        //     "ids" => $ids,
        //     "attachment_present" => $attachment !== null,
        //     "attachment_class" => $attachment ? get_class($attachment) : "null",
        // ]);

        // if ($attachment) {
        //     \Log::error(
        //         "ATTACHMENT RECEIVED: " . $attachment->getClientOriginalName()
        //     );
        // } else {
        //     \Log::error("NO ATTACHMENT RECEIVED");
        // }

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

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

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

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

        $attachmentPath = null;
        if ($attachment) {
            // \Log::info("Attachment check passed, processing...");
            $batchIds = $recordsToSave
                ->pluck("batch_id")
                ->unique()
                ->toArray();

            // \Log::info("Batch IDs for attachment", ["batch_ids" => $batchIds]);
            $attachmentPath = $this->saveAttachmentToBatch(
                $attachment,
                $batchIds
            );

            // \Log::info("Attachment save result", ["path" => $attachmentPath]);
        }

        // \Log::warning("No attachment provided or attachment check failed");

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

        $loadings = ChickenLoadingHeaders::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.loading"),
                $record->id,
                "status_changed_to_saved",
                null,
                null,
                $auditData
            );
        }

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

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

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

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

            Batches::whereIn("id", $batchIds)->update([
                "attachment_path" => $path,
                "attachment_uploaded_at" => now(),
            ]);


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

    public function voidLoading($id)
    {
        $loading = ChickenLoadingHeaders::query()
            ->whereKey($id)
            ->where("status", "!=", "void")
            ->with(["batch:id,batch_no", "batch.transactions:id,batch_id"])
            ->first();

        if (!$loading) {
            return null;
        }

        if ($loading->status === __("models.lc_save")) {
            return false;
        }

        if ($loading->batch) {
            $loading->batch->update([
                "status" => __("models.lc_void"),
            ]);
            $loading->delete();
            $loading->batch?->transactions()->delete();
        }

        $loading->loadingLines()->delete();
        $loading->update([
            "status" => __("models.lc_void"),
        ]);
        $loading->delete();

        $this->auditTrail->log(
            __("models.transaction"),
            __("models.loading"),
            $loading->id,
            "voided",
            null,
            null,
            [
                "loading_id" => $id,
                "status" => __("models.lc_void"),
                "batch_id" => $loading->batch ? $loading->batch->id : null,
                "batch_no" => $loading->batch_no
                    ? $loading->batch->batch_no
                    : null,
            ]
        );

        return $loading;
    }

    public function viewAttachment($batchId)
    {
        $batch = Batches::find($batchId);

        if (!$batch) {
            return null;
        }

        if (
            !$batch->attachment_path ||
            !Storage::disk("public")->exists($batch->attachment_path)
        ) {
            return false;
        }

        return $batch->attachment_path;
    }

    public function createFromSync(array $data)
    {
        if (!$this->hasSyncChanges($data)) {
            return ['no_changes' => true, 'synced_id' => $data['synced_id']];
        }

        $batch = Batches::updateOrCreate(
            ['synced_id' => $data['batch_synced_id']],
            [
                "farm_id"            => $data["farm_id"],
                "farm_name"          => $data["farm_name"],
                "building_id"        => $data["building_id"],
                "building_name"      => $data["building_name"],
                "batch_no"           => $data["batch_no"],
                "batch_sequence"     => $data["batch_sequence"],
                "start_date"         => $data["loading_date"],
                "status"             => $data["batch_status"],
                "synced_status"      => "synced",
                "synced_at"          => $data["synced_at"],
                "synced_id"          => $data["synced_id"],
                "initial_population" => $data["total_initial"],
                "current_population" => $data["total_net"],
            ]
        );

        $existingHeader = ChickenLoadingHeaders::with("loadingLines")->where('synced_id', $data['synced_id'])->first();
        $oldData = $existingHeader?->getAttributes();

        $header = ChickenLoadingHeaders::updateOrCreate(
            ['synced_id' => $data['synced_id']],
            [
                "loading_date"   => $data["loading_date"],
                "farm_id"        => $data["farm_id"],
                "farm_name"      => $data["farm_name"],
                "building_id"    => $data["building_id"],
                "building_name"  => $data["building_name"],
                "batch_id"       => $batch->id,
                "batch_no"       => $batch->batch_no,
                "lead_man_id"    => $data["lead_man_id"] ?? auth()->id(),
                "caretaker_id"   => $data["caretaker_id"],
                "total_initial"  => $data["total_initial"],
                "total_reject"   => $data["total_reject"],
                "total_doa"      => $data["total_doa"],
                "total_net"      => $data["total_net"],
                "sample_count"   => $data["sample_count"],
                "status"         => $data["status"],
                "synced_status"  => "synced",
                "synced_at"      => $data["synced_at"],
            ]
        );

        foreach ($data["lines"] as $line) {
            ChickenLoadingLine::updateOrCreate(
                [
                    'synced_id' => $line['synced_id'],
                ],
                [
                    "header_id"          => $header->id,
                    "breeder_id"         => $line["breeder_id"],
                    "breeder_name"       => $line["breeder_name"],
                    "class_id"           => $line["class_id"],
                    "class_name"         => $line["class_name"],
                    "initial_population" => $line["initial_population"],
                    "reject"             => $line["reject"],
                    "doa"                => $line["doa"],
                    "loaded_at"          => $line["loaded_at"],
                ]
            );
            $incomingSyncedIds[] = $line['synced_id'];
        }

        ChickenLoadingLine::where('header_id', $header->id)
            ->whereNotIn('synced_id', $incomingSyncedIds)
            ->delete();

        Transaction::updateOrCreate(
            [
                'transaction_id'   => $header->id,
                'transaction_type' => 'chick_loading',
            ],
            [
                "batch_id"         => $batch->id,
                "farm_id"          => $data["farm_id"],
                "farm_name"        => $data["farm_name"],
                "building_id"      => $data["building_id"],
                "building_name"    => $data["building_name"],
                "quantity"         => $data["total_net"],
                "transaction_date" => $data["loading_date"],
                "remarks"          => "Synced chick loading for batch {$batch->batch_no}",
                "created_by"       => $data["lead_man_id"] ?? auth()->id(),
            ]
        );

        $actionBy = User::find($data['lead_man_id']);

        $this->auditTrail->log(
            __("models.transaction"),
            __("models.loading"),
            $header->id,
            "synced",
            $header,
            $oldData,
            $data,
            $actionBy
        );

        return $header->load('batch');
    }

    protected function hasSyncChanges(array $data): bool
    {
        $headerExists = ChickenLoadingHeaders::where('synced_id', $data['synced_id'])->first();

        if (!$headerExists) {
            return true; // new record, proceed
        }

        // Check header
        $headerExists->fill([
            "loading_date"  => $data["loading_date"],
            "farm_id"       => $data["farm_id"],
            "building_id"   => $data["building_id"],
            "caretaker_id"  => $data["caretaker_id"],
            "total_initial" => $data["total_initial"],
            "total_reject"  => $data["total_reject"],
            "total_doa"     => $data["total_doa"],
            "total_net"     => $data["total_net"],
            "sample_count"  => $data["sample_count"],
        ]);

        if ($headerExists->isDirty()) {
            return true;
        }

        // Check batch
        $batchExists = Batches::where('synced_id', $data['synced_id'])->first();
        if ($batchExists) {
            $batchExists->fill([
                "farm_id"            => $data["farm_id"],
                "building_id"        => $data["building_id"],
                "start_date"         => $data["loading_date"],
                "initial_population" => $data["total_initial"],
                "current_population" => $data["total_net"],
            ]);

            if ($batchExists->isDirty()) {
                return true;
            }
        }

        // Check lines
        foreach ($data['lines'] as $line) {
            $lineExists = ChickenLoadingLine::where('synced_id', $line['synced_id'])->first();

            if (!$lineExists) {
                return true; // new line added
            }

            $lineExists->fill([
                "breeder_id"         => $line["breeder_id"],
                "class_id"           => $line["class_id"],
                "initial_population" => $line["initial_population"],
                "reject"             => $line["reject"],
                "doa"                => $line["doa"],
                "loaded_at"          => $line["loaded_at"],
            ]);

            if ($lineExists->isDirty()) {
                return true;
            }
        }

        // Check if lines were deleted on mobile
        $existingLineCount = ChickenLoadingLine::where('header_id', $headerExists->id)->count();
        if ($existingLineCount !== count($data['lines'])) {
            return true;
        }

        return false; // nothing changed
    }

    public function syncTransaction(array $data)
    {
        $synced = [];
        $failed = [];

        foreach ($data as $transaction) {
            try {
                DB::transaction(function () use ($transaction, &$synced) {
                    $result = $this->createFromSync($transaction);

                    if (isset($result['no_changes'])) {
                        $synced[] = [
                            'synced_id'  => $transaction['synced_id'],
                            'no_changes' => true,
                        ];
                        return;
                    }

                    $synced[] = [
                        'synced_id' => $transaction['synced_id'],
                        'header_id' => $result->id,
                        'batch_id'  => $result->batch_id,
                        'batch_no'  => $result->batch_no,
                    ];
                });
            } catch (\Exception $e) {
                $failed[] = [
                    'synced_id' => $transaction['synced_id'],
                    'error'     => $e->getMessage(),
                ];
            }
        }

        return [
            'synced' => $synced,
            'failed' => $failed,
        ];
    }
}
