<?php

namespace App\Services\Support;

use App\Jobs\SendEmailJob;
use App\Models\Admin;
use App\Models\Attachment;
use App\Models\EmailTemplate;
use App\Models\Log;
use App\Models\Ticket;
use App\Models\TicketReply;
use App\Models\TicketStatus;
use Illuminate\Support\Facades\DB;
use InvalidArgumentException;
use RuntimeException;

/**
 * PRC-66 — merge one ticket INTO another. Source replies + attachments
 * are re-parented to the target; source ticket gets status=merged +
 * merged_into_ticket_id pointer (one-way; no unmerge).
 *
 * PRC-338 — cross-client merge is ALWAYS rejected (privacy /
 * data-leakage guard; the ticket_merge_allow_cross_client toggle was
 * removed — no rational use case for merging two clients' tickets).
 */
class TicketMergeService
{
    /**
     * @param  bool  $notify  PRC-298 — opt-in client email notification.
     *                        Caller (TicketMergeController) reads modal
     *                        checkbox + ticket_merge_notify_client_default
     *                        setting and passes through.
     */
    public function merge(Ticket $source, Ticket $target, Admin $admin, bool $notify = false): Ticket
    {
        if ($source->id === $target->id) {
            throw new InvalidArgumentException('Cannot merge a ticket into itself');
        }
        if ($source->merged_into_ticket_id !== null) {
            throw new InvalidArgumentException('Source ticket is already merged');
        }

        // PRC-338 — cross-client merge is always rejected (privacy guard).
        if ($source->client_id !== $target->client_id) {
            throw new InvalidArgumentException('Cross-client ticket merge is not allowed');
        }

        $mergedStatus = TicketStatus::where('slug', 'merged')->first();
        if (! $mergedStatus) {
            throw new RuntimeException('Merged ticket status missing — run migrations');
        }

        return DB::transaction(function () use ($source, $target, $admin, $mergedStatus, $notify) {
            // Move replies — preserve created_at + author
            $replyIds = TicketReply::where('ticket_id', $source->id)->pluck('id');
            TicketReply::whereIn('id', $replyIds)->update(['ticket_id' => $target->id]);

            // Move attachments uploadable_id → target ticket id
            // (attachments live on TicketReply, but caller might attach directly to ticket too)
            Attachment::where('uploadable_type', Ticket::class)
                ->where('uploadable_id', $source->id)
                ->update(['uploadable_id' => $target->id]);

            // Activity log BEFORE commit (CLAUDE.md)
            Log::create([
                'type' => Log::TYPE_ADMIN,
                'observer' => $admin->name,
                'module' => 'ticket',
                'method' => 'merged',
                'admin_id' => $admin->id,
                'client_id' => $source->client_id,
                'ip_address' => request()?->ip() ?? '0.0.0.0',
                'user_agent' => request()?->userAgent(),
                'description' => "Merged ticket #{$source->id} into #{$target->id}",
                'request' => [
                    'source_ticket_id' => $source->id,
                    'target_ticket_id' => $target->id,
                    'replies_moved' => $replyIds->count(),
                ],
            ]);

            // Mark source merged
            $source->update([
                'status_id' => $mergedStatus->id,
                'merged_into_ticket_id' => $target->id,
                'merged_at' => now(),
                'merged_by_admin_id' => $admin->id,
            ]);

            // PRC-298 — opt-in client notification. Dispatched within the
            // transaction; the queue worker runs the job after commit so
            // even if the email job fails the merge stays.
            if ($notify && $source->client_id) {
                $template = EmailTemplate::where('name', 'Support Ticket Merged')
                    ->where('status', 'active')
                    ->first();

                if ($template) {
                    SendEmailJob::dispatch(
                        'Support Ticket Merged',
                        'client',
                        $source->client_id,
                        [
                            'TICKET_ID' => (string) $source->id,
                            'TICKET_TITLE' => (string) $source->title,
                            'TARGET_TICKET_ID' => (string) $target->id,
                            'TARGET_TITLE' => (string) $target->title,
                            'MERGED_AT' => now()->format('d.m.Y H:i'),
                            'MERGED_BY_ADMIN_NAME' => (string) $admin->name,
                            'TARGET_TICKET_URL' => url('/clientarea/tickets/' . $target->id),
                        ]
                    );
                }
            }

            return $target->fresh();
        });
    }
}
