<?php

namespace App\Http\Controllers\Agency\Operation;

use App\Http\Controllers\Controller;
use App\Models\Agency\AgencyContract;
use App\Models\Chat\Conversation;
use App\Models\Operation\ResourceContract;
use App\Models\ResourceSchedule;
use App\Services\Operation\ContractDiskService;
use App\Services\Operation\ContractPdfService;
use App\Services\Operation\ContractRenderService;
use App\Services\Operation\OperationService;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class ResourceContractController extends Controller
{
    public function __construct(
        private OperationService $ops,
        private ContractRenderService $renderer,
        private ContractPdfService $pdf,
        private ContractDiskService $disk,
    ) {
    }

    private function agencyId(): int
    {
        return Auth::user()->currentAgencyId();
    }

    private function resolveOrFail(string $type, int $id): Model
    {
        $date = $this->ops->resolveByKey($type, $id);
        abort_if(!$date, 404);
        $tour = $this->ops->tourOf($date);
        abort_if(!$tour || (int) $tour->agency_id !== $this->agencyId(), 403, 'Bu işlem için yetkiniz yok.');
        return $date;
    }

    private function guardContract(ResourceContract $contract): void
    {
        abort_if((int) $contract->agency_id !== $this->agencyId(), 403, 'Bu işlem için yetkiniz yok.');
    }

    /**
     * Bir atamaya bağlı kullanılabilir şablonları + manuel alanları döndürür (modal için).
     * GET operations/{type}/{id}/resources/{schedule}/contract/options
     */
    public function options(string $type, int $id, int $schedule)
    {
        $this->resolveOrFail($type, $id);
        $sched = $this->findSchedule($schedule);

        $templates = AgencyContract::where('agency_id', $this->agencyId())
            ->forResourceRole($sched->effective_role)->where('is_active', true)
            ->orderByDesc('is_system')->orderBy('title')
            ->get(['id', 'title', 'merge_fields']);

        $data = $templates->map(function ($t) {
            $manual = collect($t->merge_fields ?? [])
                ->filter(fn ($f) => ($f['mode'] ?? 'auto') === 'manual')
                ->map(fn ($f) => ['token' => $f['token'], 'label' => $f['label'] ?? $f['token']])
                ->values();
            return ['id' => $t->id, 'title' => $t->title, 'manual_fields' => $manual];
        });

        $existing = ResourceContract::byAgency($this->agencyId())
            ->where('schedule_id', $sched->id)
            ->orderByDesc('id')
            ->get(['id', 'title', 'status', 'created_at']);

        return response()->json([
            'templates' => $data,
            'existing' => $existing->map(fn ($c) => [
                'id' => $c->id,
                'title' => $c->title,
                'status' => $c->status,
                'status_label' => $c->status_label,
                'status_color' => $c->status_color,
                'created_at' => $c->created_at?->format('d.m.Y H:i'),
            ]),
            'resource_name' => $sched->resource->name ?? 'Kaynak',
        ]);
    }

    /**
     * Şablondan kontrat üretir.
     * POST operations/{type}/{id}/resources/{schedule}/contract
     */
    public function generate(Request $request, string $type, int $id, int $schedule)
    {
        $this->resolveOrFail($type, $id);
        $sched = $this->findSchedule($schedule);

        $validated = $request->validate([
            'template_id' => 'required|integer',
            'manual' => 'nullable|array',
        ]);

        $template = AgencyContract::where('agency_id', $this->agencyId())
            ->forResourceRole($sched->effective_role)
            ->findOrFail($validated['template_id']);

        $rendered = $this->renderer->render($template, $sched, $validated['manual'] ?? []);

        $contract = ResourceContract::create([
            'agency_id' => $this->agencyId(),
            'schedule_id' => $sched->id,
            'template_id' => $template->id,
            'resource_id' => $sched->resource_id,
            'title' => $rendered['title'],
            'content' => $rendered['content'],
            'merge_data' => $rendered['merge_data'],
            'status' => 'draft',
        ]);

        // Atamayı en güncel kontrata bağla.
        $sched->update(['contract_id' => $contract->id]);

        return response()->json([
            'success' => true,
            'contract' => $this->payload($contract),
            'message' => 'Kontrat oluşturuldu.',
        ]);
    }

    /**
     * Kontrat örneğini döndürür (düzenleme modalı için).
     * GET resource-contracts/{contract}
     */
    public function show(ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);
        return response()->json(['success' => true, 'contract' => $this->payload($resourceContract)]);
    }

    /**
     * Düzenlenen içeriği kaydeder.
     * PUT resource-contracts/{contract}
     */
    public function update(Request $request, ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);

        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'content' => 'required|string',
        ]);

        $resourceContract->update([
            'title' => $validated['title'],
            'content' => $validated['content'],
        ]);

        // Diske (Sözleşmeler / {Rehber}) belge olarak kaydet
        $diskNote = '';
        try {
            $this->disk->store($resourceContract->fresh(['resource', 'schedule.resource']));
            $diskNote = $this->pdf->available()
                ? ' PDF olarak Disk\'e kaydedildi.'
                : ' Disk\'e kaydedildi (HTML — PDF için barryvdh/laravel-dompdf kurun).';
        } catch (\Throwable $e) {
            report($e);
            $diskNote = ' (Disk\'e kaydedilemedi.)';
        }

        return response()->json(['success' => true, 'message' => 'Kontrat kaydedildi.' . $diskNote, 'contract' => $this->payload($resourceContract)]);
    }

    /**
     * Kontratı "gönderildi" olarak işaretler (chat göndermeden).
     * POST resource-contracts/{contract}/send
     */
    public function send(ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);

        $resourceContract->update(['status' => 'sent', 'sent_at' => now()]);

        return response()->json([
            'success' => true,
            'message' => 'Kontrat gönderildi olarak işaretlendi.',
            'contract' => $this->payload($resourceContract),
        ]);
    }

    /**
     * Kontratı rehbere CHAT üzerinden dosya (HTML) olarak gönderir ve durumu sent yapar.
     * POST resource-contracts/{contract}/send-to-guide
     */
    public function sendToChat(ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);
        $resourceContract->loadMissing('resource.user', 'schedule.resource.user');

        $resource = $resourceContract->resource ?: optional($resourceContract->schedule)->resource;
        $guideUser = $resource?->user;

        if (!$guideUser) {
            return response()->json([
                'success' => false,
                'message' => 'Bu kaynağın bağlı bir kullanıcı hesabı yok; chat ile gönderilemiyor. Önce Kaynak Yönetimi\'nden bu kaynağa bir kullanıcı bağlayın.',
            ], 422);
        }

        // Birebir sohbeti bul/oluştur
        $conversation = Conversation::findOrCreateDm((int) Auth::id(), (int) $guideUser->id);

        // Belge (PDF varsa PDF, yoksa HTML) üret ve public diske yaz
        $doc = $this->pdf->document($resourceContract);
        $slug = Str::slug($resourceContract->title ?: 'sozlesme') ?: 'sozlesme';
        $path = 'chat/' . $conversation->id . '/' . $slug . '-' . $resourceContract->id . '.' . $doc['extension'];
        Storage::disk('public')->put($path, $doc['content']);

        // Mesaj + ek
        $message = $conversation->messages()->create([
            'sender_id' => Auth::id(),
            'resource_contract_id' => $resourceContract->id,
            'body' => '📄 ' . $resourceContract->title . ' — hizmet sözleşmeniz ektedir. Lütfen inceleyip onaylayın.',
            'has_attachments' => true,
        ]);
        $message->attachments()->create([
            'path' => $path,
            'original_name' => $slug . '.' . $doc['extension'],
            'mime_type' => $doc['mime'],
            'size' => strlen($doc['content']),
            'kind' => 'file',
        ]);
        $conversation->update(['last_message_at' => now()]);

        // Reverb yayını (soket açıksa rehbere anında düşer; hata gönderimi bozmaz)
        try {
            $participantIds = $conversation->participants()->pluck('user_id')->map(fn ($v) => (int) $v)->all();
            broadcast(new \App\Events\Chat\MessageSent($conversation->id, (int) Auth::id(), $participantIds));
        } catch (\Throwable $e) {
            report($e);
        }

        // Durumu sent yap
        $resourceContract->update(['status' => 'sent', 'sent_at' => now()]);

        return response()->json([
            'success' => true,
            'message' => trim(($guideUser->first_name ?? '') . ' ' . ($guideUser->last_name ?? '')) . ' adlı rehbere sohbet üzerinden gönderildi.',
            'contract' => $this->payload($resourceContract),
            'conversation_id' => $conversation->id,
        ]);
    }


    /**
     * Kontratı imzalandı/reddedildi olarak işaretler.
     * POST resource-contracts/{contract}/status
     */
    public function setStatus(Request $request, ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);
        $validated = $request->validate(['status' => 'required|in:draft,sent,signed,declined']);

        $resourceContract->update([
            'status' => $validated['status'],
            'signed_at' => $validated['status'] === 'signed' ? now() : $resourceContract->signed_at,
        ]);

        return response()->json(['success' => true, 'contract' => $this->payload($resourceContract)]);
    }

    /**
     * DELETE resource-contracts/{contract}
     * Kontrat silinir; rehbere chat'ten gönderildiyse ilgili mesaj(lar) "iptal edildi"
     * olarak işaretlenir ve ekleri (dosya) kaldırılır.
     */
    public function destroy(ResourceContract $resourceContract)
    {
        $this->guardContract($resourceContract);

        // Bu kontratı taşıyan chat mesajlarını iptal edildi işaretle + eklerini sil
        $messages = \App\Models\Chat\Message::where('resource_contract_id', $resourceContract->id)
            ->whereNull('revoked_at')
            ->with('attachments')
            ->get();

        foreach ($messages as $message) {
            foreach ($message->attachments as $att) {
                Storage::disk('public')->delete($att->path);
                $att->delete();
            }
            $message->update(['revoked_at' => now(), 'has_attachments' => false, 'links' => null]);
        }

        // Disk modülündeki dosyayı (fiziksel + kayıt) kaldır.
        try {
            $this->disk->removeExisting($resourceContract);
        } catch (\Throwable $e) {
            report($e);
        }

        // Atama bu kontrata bağlıysa bağı kaldır.
        ResourceSchedule::where('contract_id', $resourceContract->id)->update(['contract_id' => null]);
        $resourceContract->delete();

        return response()->json([
            'success' => true,
            'message' => $messages->count()
                ? 'Kontrat silindi ve sohbette iptal edildi olarak işaretlendi.'
                : 'Kontrat silindi.',
        ]);
    }

    // ─── Dahili ──────────────────────────────────────────────────

    private function findSchedule(int $schedule): ResourceSchedule
    {
        return ResourceSchedule::where('agency_id', $this->agencyId())
            ->with('resource')
            ->findOrFail($schedule);
    }

    private function payload(ResourceContract $c): array
    {
        return [
            'id' => $c->id,
            'title' => $c->title,
            'content' => $c->content,
            'status' => $c->status,
            'status_label' => $c->status_label,
            'status_color' => $c->status_color,
            'sent_at' => $c->sent_at?->format('d.m.Y H:i'),
        ];
    }
}
