<?php

namespace App\Http\Controllers\Agency\Customer;

use App\Http\Controllers\Controller;
use App\Models\Customer\Customer;
use App\Models\Mail\MailAccount;
use App\Models\Mail\MailAttachment;
use App\Models\Mail\MailMessage;
use App\Services\Mail\MailCustomerLinker;
use App\Services\Mail\MailHtmlSanitizer;
use App\Services\Mail\MailSendService;
use App\Services\Mail\MailSyncService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

/**
 * Müşteri kartı ↔ mail modülü köprüsü.
 *
 * Müşteri kartındaki yazışma akışı ve "E-posta" yazma kutusu buradan çalışır:
 * gönderim mail modülünün SMTP servisiyle yapılır, gönderilen posta müşteriye
 * bağlanır ve etkinlik akışında görünür.
 */
class CustomerMailController extends Controller
{
    public function __construct(
        private MailSendService $sender,
        private MailSyncService $sync,
        private MailCustomerLinker $linker,
    ) {}

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

    private function authorizeAgency(Customer $customer): void
    {
        abort_unless((int) $customer->agency_id === $this->agencyId(), 403, 'Bu müşteriye erişiminiz yok.');
    }

    /** Kullanıcının gönderim yapabileceği hesaplar: acente geneli + kendi hesapları. */
    private function accountsQuery()
    {
        $userId = (int) Auth::id();

        return MailAccount::where('agency_id', $this->agencyId())
            ->where('is_active', true)
            ->where(fn ($q) => $q->whereNull('user_id')->orWhere('user_id', $userId))
            ->orderByDesc('is_default')
            ->orderBy('sort_order')
            ->orderBy('id');
    }

    /**
     * Kullanıcının okuyabileceği hesaplar: acente geneli + kendi hesapları.
     *
     * Kişisel hesaplar (user_id dolu) yalnızca sahibinindir; müşteri kartı da
     * mail modülüyle aynı kapsamı uygulamak zorunda — aksi hâlde bir kullanıcı
     * başkasının özel yazışmasını kart üzerinden okuyabilir.
     */
    private function accountIds(): array
    {
        $userId = (int) Auth::id();

        return MailAccount::where('agency_id', $this->agencyId())
            ->where(fn ($q) => $q->whereNull('user_id')->orWhere('user_id', $userId))
            ->pluck('id')->map(fn ($v) => (int) $v)->all();
    }

    // ─────────────────────────────────────────── okuma

    /** Tek yazışmanın gövdesi — kart içindeki okuyucu için. */
    public function show(Customer $customer, int $message): JsonResponse
    {
        $this->authorizeAgency($customer);

        $mail = MailMessage::where('customer_id', $customer->id)
            ->whereIn('account_id', $this->accountIds())
            ->with(['folder', 'account', 'attachments'])
            ->findOrFail($message);

        $error = null;
        if (! $mail->body_fetched_at) {
            try {
                $mail = $this->sync->ensureBody($mail);
                $mail->load(['folder', 'account', 'attachments']);
            } catch (\Throwable $e) {
                $error = 'İleti içeriği sunucudan alınamadı: '.$e->getMessage();
            } finally {
                $this->sync->closeAll();
            }
        }

        return response()->json([
            'id' => $mail->id,
            'subject' => $mail->subject ?: '(konu yok)',
            'direction' => $mail->direction(),
            'from' => ['name' => $mail->from_name, 'email' => $mail->from_email],
            'to' => collect($mail->to_json ?: [])->pluck('email')->filter()->implode(', '),
            'cc' => collect($mail->cc_json ?: [])->pluck('email')->filter()->implode(', '),
            'date_full' => optional($mail->date_at)->translatedFormat('d F Y, H:i'),
            'body_html' => $mail->body_html
                ? MailHtmlSanitizer::clean($mail->body_html, $mail, false)
                : MailHtmlSanitizer::fromText($mail->body_text),
            'attachments' => $mail->attachments->where('is_inline', false)->values()
                ->map(fn (MailAttachment $a) => [
                    'filename' => $a->filename,
                    'size' => $a->humanSize(),
                    'icon' => $a->icon(),
                    'download_url' => route('agency.mail.attachments.download', $a->id),
                ])->all(),
            'reply' => [
                'to' => $mail->direction() === 'inbound'
                    ? $mail->from_email
                    : collect($mail->to_json ?: [])->pluck('email')->filter()->implode(', '),
                'subject' => 'Ynt: '.preg_replace('/^(\s*(re|ynt|fwd|fw|ilt)\s*:\s*)+/iu', '', (string) $mail->subject),
                'account_id' => $mail->account_id,
                'in_reply_to' => $mail->message_id,
                'references' => implode(' ', array_slice(
                    array_merge($mail->references_json ?: [], array_filter([$mail->message_id])), -20
                )),
            ],
            'error' => $error,
        ]);
    }

    // ─────────────────────────────────────────── gönderme

    /** Müşteriye doğrudan e-posta gönderir ve postayı karta bağlar. */
    public function send(Request $request, Customer $customer): JsonResponse
    {
        $this->authorizeAgency($customer);

        $validated = $request->validate([
            'account_id' => 'required|integer',
            'identity_id' => 'nullable|integer',
            'to' => 'required|string|max:2000',
            'cc' => 'nullable|string|max:2000',
            'bcc' => 'nullable|string|max:2000',
            'subject' => 'nullable|string|max:900',
            'body_html' => 'required|string',
            'in_reply_to' => 'nullable|string|max:512',
            'references' => 'nullable|string',
            'attachments.*' => 'file|max:25600',
        ]);

        $account = $this->accountsQuery()->find((int) $validated['account_id']);
        if (! $account) {
            return response()->json(['success' => false, 'message' => 'E-posta hesabı bulunamadı.'], 422);
        }

        /*
         * Gönderici profili: adres hesaba aittir, profil yalnızca From: başlığındaki
         * görünen adı (ve imzayı) değiştirir. Profilin SEÇİLEN HESABA ait olduğu
         * burada doğrulanır — aksi hâlde istemciye elle "identity_id" eklenerek
         * başka bir birimin adıyla yazışılabilirdi.
         */
        $identityId = isset($validated['identity_id']) ? (int) $validated['identity_id'] : null;
        if ($identityId && ! $account->identities()->whereKey($identityId)->exists()) {
            return response()->json([
                'success' => false,
                'message' => 'Seçilen gönderici profili bu e-posta hesabına ait değil.',
            ], 422);
        }

        $data = [
            'identity_id' => $identityId,
            'to' => \App\Services\Mail\MimeParser::parseAddressList($validated['to']),
            'cc' => \App\Services\Mail\MimeParser::parseAddressList($validated['cc'] ?? null),
            'bcc' => \App\Services\Mail\MimeParser::parseAddressList($validated['bcc'] ?? null),
            'subject' => (string) ($validated['subject'] ?? ''),
            'body_html' => (string) $validated['body_html'],
            'priority' => 3,
            'in_reply_to' => $validated['in_reply_to'] ?? null,
            'references' => array_filter(explode(' ', (string) ($validated['references'] ?? ''))),
            'attachments' => $request->file('attachments', []),
            'keep_attachments' => collect(),
            'append_signature' => $request->boolean('append_signature'),
        ];

        if (! $data['to']) {
            return response()->json(['success' => false, 'message' => 'Geçerli bir alıcı adresi girin.'], 422);
        }

        try {
            $messageId = $this->sender->send($account, $data);
        } catch (\Throwable $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 422);
        } finally {
            $this->sync->closeAll();
        }

        // Gönderilen posta müşteri kartına bağlanır → etkinlik akışında görünür
        $local = $this->sender->localSentMessage($account, $messageId);
        if ($local) {
            $this->linker->attach($local, $customer);
        }

        return response()->json([
            'success' => true,
            'message' => 'E-posta gönderildi.',
            'mail_id' => $local?->id,
        ]);
    }

    // ─────────────────────────────────────────── elle bağ

    /** Yanlış eşleşen ya da elle eklenmek istenen bir postayı karttan çıkarır. */
    public function detach(Customer $customer, int $message): JsonResponse
    {
        $this->authorizeAgency($customer);

        $mail = MailMessage::where('customer_id', $customer->id)
            ->whereIn('account_id', $this->accountIds())
            ->findOrFail($message);

        $mail->forceFill(['customer_id' => null])->save();

        return response()->json(['success' => true, 'message' => 'Yazışma karttan çıkarıldı.']);
    }
}
