<?php

namespace App\Http\Controllers;

use App\Models\OperationalDocument;
use App\Models\Project;
use App\Models\TradeDocument;
use App\Models\User;
use App\Models\ContactEmail;
use App\Models\CrmCase;
use App\Services\CaseNumberService;
use App\Services\CrmNotificationService;
use Illuminate\Support\Facades\Mail;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class OperationalDocumentController extends Controller
{
    private function definition(string $type): array
    {
        $definitions = [
            'sales-orders' => ['title'=>'Sales Orders','reference'=>'Sales Order No','status'=>['draft','pending_approval','approved','partially_delivered','completed','closed','cancelled','expired'],'fields'=>[
                'order_date'=>'date','account_id'=>'account','contact_id'=>'contact','deal_id'=>'deal','quotation_number'=>'text','salesperson_id'=>'user','currency'=>'text','payment_terms'=>'text','delivery_terms'=>'text','billing_address'=>'textarea','delivery_address'=>'textarea','products_services'=>'textarea','subtotal'=>'number','discount_amount'=>'number','tax_amount'=>'number','other_charges'=>'number','grand_total'=>'number','notes'=>'textarea','terms_conditions'=>'textarea','attachment_reference'=>'text','expected_delivery_date'=>'date','approval_status'=>'select:draft,pending_approval,approved,rejected,revised']],
            'contracts' => ['title'=>'Contracts','reference'=>'Contract No','status'=>['draft','internal_review','approved','sent_to_customer','active','renewed','expired','archived'],'fields'=>[
                'contract_name'=>'text','contract_type'=>'select:software_development,saas_subscription,software_licence,implementation,maintenance_support,service,consulting,nda,integration','account_id'=>'account','contact_id'=>'contact','contract_date'=>'date','start_date'=>'date','end_date'=>'date','currency'=>'text','contract_value'=>'number','billing_cycle'=>'select:one_time,monthly,quarterly,half_yearly,yearly','renewal_type'=>'select:manual,automatic,non_renewable','notice_period_days'=>'number','payment_terms'=>'text','deliverables'=>'textarea','sla_reference'=>'text','scope_of_work'=>'textarea','terms_conditions'=>'textarea','contract_document'=>'text','attachment_reference'=>'text']],
            'handovers' => ['title'=>'Project Handovers','reference'=>'Handover No','status'=>['draft','pending','returned','approved','handed_over','cancelled'],'fields'=>[
                'project_name'=>'text','account_id'=>'account','contact_id'=>'contact','deal_id'=>'deal','contract_number'=>'text','salesperson_id'=>'user','project_manager_id'=>'user','reviewer_id'=>'user','project_team'=>'textarea','project_type'=>'text','project_start_date'=>'date','project_end_date'=>'date','project_value'=>'number','payment_terms'=>'text','scope_of_work'=>'textarea','requirements'=>'textarea','products_services'=>'textarea','modules_features'=>'textarea','technology_stack'=>'textarea','milestones'=>'textarea','deliverables'=>'textarea','client_instructions'=>'textarea','handover_checklist'=>'textarea','attachment_reference'=>'text']],
            'deliveries' => ['title'=>'Deliveries','reference'=>'Delivery ID','status'=>['planned','ready_for_delivery','in_progress','internal_qa','uat','customer_approval','deployment','go_live','delivered','customer_sign_off','closed'],'fields'=>[
                'delivery_name'=>'text','account_id'=>'account','contact_id'=>'contact','sales_order_reference'=>'text','project_id'=>'project','delivery_type'=>'select:implementation,installation,deployment,configuration,training,support,release','delivery_manager_id'=>'user','delivery_team'=>'textarea','progress'=>'number','version_release'=>'text','environment'=>'select:development,test,uat,staging,production,customer_site','deployment_details'=>'textarea','installation_details'=>'textarea','uat_status'=>'select:not_started,in_progress,passed,failed,waived','approval_status'=>'select:pending,approved,rejected','handover_document'=>'text','release_notes'=>'textarea','issues_exceptions'=>'textarea','completion_owner_id'=>'user','completion_date'=>'date','planned_delivery_date'=>'date','actual_delivery_date'=>'date','milestone_reference'=>'text','deliverables'=>'textarea','uat_evidence_reference'=>'text','customer_sign_off_reference'=>'text','defects_notes'=>'textarea','attachment_reference'=>'text']],
            'invoices' => ['title'=>'Invoices','reference'=>'Invoice No','status'=>['draft','pending_approval','approved','sent','partially_paid','paid','closed','cancelled'],'fields'=>[
                'invoice_date'=>'date','due_date'=>'date','account_id'=>'account','contact_id'=>'contact','sales_order_reference'=>'text','contract_reference'=>'text','project_id'=>'project','delivery_reference'=>'text','milestone_reference'=>'text','billing_address'=>'textarea','invoice_type'=>'select:advance,milestone,project,final,subscription,maintenance,recurring,support,proforma,credit_note','currency'=>'text','payment_terms'=>'text','products_services'=>'textarea','subtotal'=>'number','discount_amount'=>'number','tax_amount'=>'number','other_charges'=>'number','total_amount'=>'number','attachment_reference'=>'text','payment_status'=>'select:pending,received,under_verification,verified,allocated,completed']],
        ];
        abort_unless(isset($definitions[$type]), 404);
        return $definitions[$type];
    }

    public function index(Request $request, string $type)
    {
        $definition = $this->definition($type);
        $deliveryFilters = $request->validate(['delivery_manager_id'=>'nullable|integer','delivery_team'=>'nullable|string|max:255','version_release'=>'nullable|string|max:255','environment'=>'nullable|string|max:255','delivery_status'=>'nullable|string|max:255','completion_date'=>'nullable|date']);
        $records = OperationalDocument::where('business_id',$request->user()->business_id)->where('type',$type)->when($request->filled('record'),fn($query)=>$query->whereKey($request->integer('record')))
            ->when($type==='deliveries' && filled($deliveryFilters['delivery_manager_id']??null),fn($query)=>$query->where('details->delivery_manager_id',$deliveryFilters['delivery_manager_id']))
            ->when($type==='deliveries' && filled($deliveryFilters['delivery_team']??null),fn($query)=>$query->where('details->delivery_team','like','%'.$deliveryFilters['delivery_team'].'%'))
            ->when($type==='deliveries' && filled($deliveryFilters['version_release']??null),fn($query)=>$query->where('details->version_release',$deliveryFilters['version_release']))
            ->when($type==='deliveries' && filled($deliveryFilters['environment']??null),fn($query)=>$query->where('details->environment',$deliveryFilters['environment']))
            ->when($type==='deliveries' && filled($deliveryFilters['delivery_status']??null),fn($query)=>$query->where('status',$deliveryFilters['delivery_status']))
            ->when($type==='deliveries' && filled($deliveryFilters['completion_date']??null),fn($query)=>$query->where('details->completion_date',$deliveryFilters['completion_date']))
            ->latest()->paginate(20)->withQueryString();
        $deliveryManagers=$type==='deliveries'?User::where('business_id',$request->user()->business_id)->orderBy('name')->get():collect();
        return view('operational-documents.index', compact('type','definition','records','deliveryFilters','deliveryManagers'));
    }

    public function store(Request $request, string $type)
    {
        $definition = $this->definition($type);
        $rules = ['reference_number'=>'required|string|max:255','status'=>['required', Rule::in($definition['status'])]];
        foreach ($definition['fields'] as $name=>$kind) {
            $rules[$name] = $this->fieldRule($kind, $request, $type !== 'deliveries');
        }
        $data = $request->validate($rules);
        if ($type === 'deliveries') $this->requireArrayDetails($data, $this->deliveryRequiredFields($data['status']));
        OperationalDocument::create([
            'business_id'=>$request->user()->business_id, 'type'=>$type, 'reference_number'=>$data['reference_number'],
            'account_id'=>$data['account_id']??null, 'contact_id'=>$data['contact_id']??null, 'deal_id'=>$data['deal_id']??null,
            'project_id'=>$data['project_id']??null, 'owner_id'=>$data['salesperson_id']??$data['delivery_manager_id']??$request->user()->id, 'status'=>$data['status'], 'details'=>$data,
        ]);
        return back()->with('success', rtrim($definition['title'],'s').' created.');
    }

    public function updateDetails(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id === $request->user()->business_id, 403);
        abort_unless(in_array($document->status, ['draft', 'returned'], true) || ($document->type === 'deliveries' && $document->status !== 'closed'), 422, 'Only editable workflow records can be updated.');
        $definition = $this->definition($document->type);
        $rules = [];
        foreach ($definition['fields'] as $name => $kind) $rules[$name] = $this->fieldRule($kind, $request, false);
        $data = $request->validate($rules);
        $details = array_merge($document->details ?? [], array_filter($data, fn ($value) => $value !== null && $value !== ''));
        if ($document->type === 'deliveries') $this->requireArrayDetails($details, $this->deliveryRequiredFields($document->status));
        $document->update([
            'account_id' => $details['account_id'] ?? $document->account_id,
            'contact_id' => $details['contact_id'] ?? $document->contact_id,
            'deal_id' => $details['deal_id'] ?? $document->deal_id,
            'project_id' => $details['project_id'] ?? $document->project_id,
            'owner_id' => $details['salesperson_id'] ?? $details['project_manager_id'] ?? $details['delivery_manager_id'] ?? $document->owner_id,
            'details' => $details,
        ]);
        return back()->with('success', 'Draft details updated.');
    }

    private function fieldRule(string $kind, Request $request, bool $required): array|string
    {
        $prefix = $required ? 'required' : 'nullable';
        return match (true) {
            str_starts_with($kind,'select:') => [$prefix, Rule::in(explode(',', substr($kind,7)))],
            $kind === 'date' => "$prefix|date",
            $kind === 'number' => "$prefix|numeric|min:0",
            $kind === 'account' => [$prefix, Rule::exists('accounts','id')->where(fn($q)=>$q->where('business_id',$request->user()->business_id))],
            $kind === 'contact' => [$prefix, Rule::exists('contacts','id')->where(fn($q)=>$q->where('business_id',$request->user()->business_id))],
            $kind === 'deal' => [$prefix, Rule::exists('deals','id')->where(fn($q)=>$q->where('business_id',$request->user()->business_id))],
            $kind === 'project' => [$prefix, Rule::exists('projects','id')->where(fn($q)=>$q->where('business_id',$request->user()->business_id))],
            $kind === 'user' => [$prefix, Rule::exists('users','id')->where(fn($q)=>$q->where('business_id',$request->user()->business_id))],
            default => "$prefix|string|max:10000",
        };
    }

    public function transition(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id === $request->user()->business_id, 403);
        $definition = $this->definition($document->type);
        $data = $request->validate(['status'=>['required', Rule::in($definition['status'])], 'comment'=>'nullable|string|max:2000']);
        $allowed = [
            'sales-orders' => ['draft'=>['pending_approval','cancelled'], 'pending_approval'=>['approved','draft','cancelled'], 'approved'=>['partially_delivered','completed','closed']],
            'contracts' => ['draft'=>['internal_review','cancelled'], 'internal_review'=>['approved','draft'], 'approved'=>['sent_to_customer'], 'sent_to_customer'=>[], 'active'=>['renewed','expired','archived']],
            'handovers' => ['draft'=>['pending','cancelled'], 'pending'=>['approved','returned'], 'returned'=>['pending','cancelled'], 'approved'=>['handed_over']],
            'deliveries' => ['planned'=>['ready_for_delivery','cancelled'], 'ready_for_delivery'=>['in_progress'], 'in_progress'=>['internal_qa'], 'internal_qa'=>['uat'], 'uat'=>['customer_approval'], 'customer_approval'=>['deployment','rejected'], 'rejected'=>['in_progress'], 'deployment'=>['go_live'], 'go_live'=>['delivered'], 'delivered'=>['customer_sign_off'], 'customer_sign_off'=>['closed']],
            'invoices' => ['draft'=>['pending_approval','cancelled'], 'pending_approval'=>['approved','draft'], 'approved'=>['sent'], 'sent'=>['partially_paid','paid'], 'partially_paid'=>['paid'], 'paid'=>['closed']],
        ];
        abort_unless(in_array($data['status'], $allowed[$document->type][$document->status] ?? [], true), 422, 'Invalid workflow transition.');
        $this->assertTransitionRequirements($document, $data['status']);
        $from = $document->status;
        if ($document->type === 'handovers' && in_array($data['status'], ['approved','returned'], true)) {
            abort_unless((int)($document->details['reviewer_id'] ?? 0) === (int)$request->user()->id, 403, 'Only the assigned handover reviewer can approve or return it.');
        }
        $updates = ['status'=>$data['status']];
        if ($data['status'] === 'approved') $updates += ['approved_at'=>now(),'approved_by'=>$request->user()->id];
        if (in_array($data['status'], ['approved','returned'], true)) {
            abort_unless($request->user()->is_admin || (int)$document->owner_id !== (int)$request->user()->id, 403, 'Owners cannot approve or return their own operational records.');
            if ($data['status'] === 'returned') abort_unless(filled($data['comment'] ?? null), 422, 'A return reason is required.');
        }
        $document->update($updates);
        $document->histories()->create(['user_id'=>$request->user()->id,'action'=>'transition','from_status'=>$from,'to_status'=>$data['status'],'comment'=>$data['comment'] ?? null]);
        if ($document->type === 'handovers' && in_array($data['status'], ['pending','approved','returned'], true)) {
            $version = (int)($document->details['handover_version'] ?? 0) + ($data['status'] === 'pending' ? 1 : 0);
            if ($data['status'] === 'pending') $document->update(['details'=>array_merge($document->details ?? [],['handover_version'=>$version])]);
            \DB::table('handover_versions')->updateOrInsert(['handover_id'=>$document->id,'version'=>$version ?: 1,'decision'=>$data['status']],['reviewer_id'=>$document->details['reviewer_id'],'comment'=>$data['comment']??null,'details_snapshot'=>json_encode($document->details),'decided_by'=>$request->user()->id,'decided_at'=>now(),'updated_at'=>now(),'created_at'=>now()]);
        }
        $this->notify($document, "{$document->type} status updated to {$data['status']}", $request);
        if ($document->type === 'handovers' && $data['status'] === 'approved') $this->createProject($document, $request);
        if ($document->type === 'deliveries' && $data['status'] === 'customer_sign_off') $this->createSupportHandoff($document, $request);
        if ($document->type === 'deliveries' && $document->project_id) {
            $project = Project::whereKey($document->project_id)->where('business_id', $document->business_id)->first();
            if ($project && $data['status'] === 'in_progress') $project->update(['status' => 'in_progress']);
            if ($project && $data['status'] === 'customer_sign_off') $project->update(['status' => 'awaiting_customer_sign_off']);
            if ($project && $data['status'] === 'closed') $project->update(['status' => 'completed', 'progress' => 100]);
        }
        if ($document->type === 'invoices') $this->syncTradeInvoiceStatus($document, $data['status']);
        return back()->with('success', 'Workflow status updated.');
    }

    public function signContract(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id === $request->user()->business_id && $document->type === 'contracts', 404);
        abort_unless($document->status === 'sent_to_customer', 422, 'Only a sent contract can be signed.');
        $data=$request->validate(['customer_signatory'=>'required|string|max:255','company_signatory'=>'required|string|max:255','signed_date'=>'required|date','signature_reference'=>'nullable|string|max:255']);
        $document->update(['details'=>array_merge($document->details ?? [],$data),'status'=>'active','approved_at'=>now(),'approved_by'=>$request->user()->id]);
        $document->histories()->create(['user_id'=>$request->user()->id,'action'=>'signed','from_status'=>'sent_to_customer','to_status'=>'active','comment'=>'Contract signed by '.$data['customer_signatory']]);
        $this->notify($document, 'Contract signed and activated', $request);
        return back()->with('success','Contract signature recorded and contract activated.');
    }

    public function rejectDelivery(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id === $request->user()->business_id && $document->type === 'deliveries', 404);
        abort_unless(in_array($document->status, ['customer_approval','delivered'], true), 422, 'Only a delivery awaiting customer approval can be rejected.');
        $data=$request->validate(['reason'=>'required|string|max:5000','affected_deliverables'=>'required|string|max:5000']);
        $assignee=$document->details['delivery_manager_id'] ?? $document->owner_id;
        $followUp=\App\Models\FollowUp::create(['business_id'=>$document->business_id,'owner_id'=>$assignee,'title'=>'Correct delivery rejection: '.$document->reference_number,'follow_up_at'=>now()->addDay(),'remind_at'=>now()->addHours(12),'priority'=>'high','status'=>'pending','notes'=>$data['reason'].' Affected deliverables: '.$data['affected_deliverables'],'related_type'=>OperationalDocument::class,'related_id'=>$document->id]);
        \DB::table('delivery_corrective_actions')->insert(['business_id'=>$document->business_id,'delivery_id'=>$document->id,'follow_up_id'=>$followUp->id,'reason'=>$data['reason'],'affected_deliverables'=>$data['affected_deliverables'],'assigned_to'=>$assignee,'status'=>'open','created_at'=>now(),'updated_at'=>now()]);
        $document->update(['status'=>'rejected']);$document->histories()->create(['user_id'=>$request->user()->id,'action'=>'customer_rejected','from_status'=>'customer_approval','to_status'=>'rejected','comment'=>$data['reason']]);
        return back()->with('success','Delivery rejected and corrective follow-up assigned.');
    }

    public function completeCorrectiveAction(Request $request, int $action)
    {
        $record=\DB::table('delivery_corrective_actions')->where('id',$action)->where('business_id',$request->user()->business_id)->first();abort_unless($record,404);
        abort_unless((int)$record->assigned_to === (int)$request->user()->id || $request->user()->is_admin,403);
        \DB::table('delivery_corrective_actions')->where('id',$action)->update(['status'=>'completed','completed_at'=>now(),'updated_at'=>now()]);
        if($record->follow_up_id) \App\Models\FollowUp::whereKey($record->follow_up_id)->update(['status'=>'completed']);
        return back()->with('success','Corrective action completed.');
    }

    public function createFromQuotation(Request $request)
    {
        $data = $request->validate(['trade_document_id'=>['required', Rule::exists('trade_documents','id')]]);
        $quote = TradeDocument::with(['deal','lines'])->whereKey($data['trade_document_id'])->where('business_id',$request->user()->business_id)->where('type','quotation')->firstOrFail();
        abort_unless($quote->status === 'accepted', 422, 'Only a customer-accepted quotation can create a Sales Order.');
        $deal = $quote->deal;
        abort_unless($deal?->account_id && $deal?->contact_id, 422, 'The accepted quotation must be linked to a Deal with an Account and primary Contact.');
        abort_unless($quote->lines->isNotEmpty(), 422, 'The accepted quotation must contain at least one line item.');
        $products = $quote->lines->map(fn ($line) => trim(($line->description ?: 'Item').' × '.$line->quantity))->filter()->implode("\n");
        $order = OperationalDocument::firstOrCreate(['business_id'=>$quote->business_id,'type'=>'sales-orders','trade_document_id'=>$quote->id], [
            'reference_number'=>'SO-'.$quote->document_number,'account_id'=>$deal?->account_id,'contact_id'=>$deal?->contact_id,'deal_id'=>$quote->deal_id,
            'owner_id'=>$request->user()->id,'status'=>'draft','details'=>[
                'order_date'=>now()->toDateString(),'account_id'=>$deal->account_id,'contact_id'=>$deal->contact_id,'deal_id'=>$quote->deal_id,
                'quotation_number'=>$quote->document_number,'salesperson_id'=>$request->user()->id,'currency'=>$quote->currency,
                'payment_terms'=>$quote->payment_terms ?: 'Due on receipt','products_services'=>$products,
                'subtotal'=>$quote->subtotal,'grand_total'=>$quote->total,'approval_status'=>'draft',
            ],
        ]);
        return redirect()->route('operational-documents.index','sales-orders')->with('success', "Sales Order {$order->reference_number} created from quotation.");
    }

    private function conversionProfile(OperationalDocument $document, string $next): array
    {
        $details = $document->details ?? [];
        $defaults = match ($next) {
            'contracts' => ['contract_name'=>$document->reference_number, 'contract_type'=>'service', 'contract_date'=>now()->toDateString(), 'start_date'=>now()->toDateString(), 'currency'=>$details['currency']??'USD', 'contract_value'=>$details['grand_total']??0, 'payment_terms'=>$details['payment_terms']??null, 'scope_of_work'=>$details['products_services']??null, 'terms_conditions'=>$details['notes']??null],
            'handovers' => ['project_name'=>$document->reference_number.' Project', 'contract_number'=>$document->reference_number, 'salesperson_id'=>$document->owner_id, 'project_type'=>'Implementation', 'scope_of_work'=>$details['scope_of_work']??null, 'requirements'=>$details['requirements']??null, 'products_services'=>$details['products_services']??null],
            'deliveries' => [
                'delivery_name'=>$document->reference_number.' Delivery','account_id'=>$document->account_id,'contact_id'=>$document->contact_id,
                'sales_order_reference'=>$this->salesOrderReference($document),'project_id'=>$document->project_id,'delivery_type'=>$details['project_type']??'implementation',
                'delivery_manager_id'=>$details['project_manager_id']??$document->owner_id,'delivery_team'=>$details['project_team']??null,'progress'=>0,
                'version_release'=>'Initial release','environment'=>'uat','deployment_details'=>$details['scope_of_work']??null,'installation_details'=>$details['requirements']??null,
                'uat_status'=>'not_started','approval_status'=>'pending','handover_document'=>$document->reference_number,'release_notes'=>$details['client_instructions']??null,
                'issues_exceptions'=>null,'completion_owner_id'=>$details['project_manager_id']??$document->owner_id,'completion_date'=>null,
                'planned_delivery_date'=>now()->toDateString(),'actual_delivery_date'=>null,'milestone_reference'=>$details['milestones']??null,
                'deliverables'=>$details['deliverables']??$details['products_services']??null,'uat_evidence_reference'=>null,'customer_sign_off_reference'=>null,'defects_notes'=>null,'attachment_reference'=>$details['attachment_reference']??null],
            'invoices' => ['invoice_date'=>now()->toDateString(), 'due_date'=>now()->addDays(30)->toDateString(), 'invoice_type'=>'final', 'currency'=>$details['currency']??'USD', 'payment_terms'=>$details['payment_terms']??null, 'products_services'=>$details['deliverables']??null, 'subtotal'=>$details['grand_total']??null, 'total_amount'=>$details['grand_total']??null, 'payment_status'=>'pending'],
        };
        $fieldKinds = $this->definition($next)['fields'];
        $mapping = [];
        foreach ($fieldKinds as $field => $kind) $mapping[$field] = $defaults[$field] ?? $details[$field] ?? null;
        foreach (['account_id', 'contact_id', 'deal_id', 'project_id'] as $field) {
            if (array_key_exists($field, $mapping)) $mapping[$field] = $defaults[$field] ?? $document->{$field};
        }

        return ['mapping' => $mapping, 'required' => $next === 'deliveries' ? $this->deliveryRequiredFields('planned') : array_keys($fieldKinds), 'fieldKinds' => $fieldKinds];
    }

    public function createNext(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id === $request->user()->business_id, 403);
        if (! $request->boolean('confirmed_preview')) return redirect()->route('operational-documents.next.preview', $document);
        $nextTypes = ['sales-orders'=>'contracts','contracts'=>'handovers','handovers'=>'deliveries','deliveries'=>'invoices'];
        $next = $nextTypes[$document->type] ?? null;
        abort_unless($next, 422, 'This record has no next workflow document.');
        $requiredStatus = ['sales-orders'=>'approved','contracts'=>'active','handovers'=>'approved','deliveries'=>'customer_sign_off'];
        abort_unless($document->status === $requiredStatus[$document->type], 422, 'Complete the required workflow approval before creating the next document.');
        if ($document->type === 'handovers') {
            abort_unless($document->project_id && Project::whereKey($document->project_id)
                ->where('business_id', $document->business_id)->whereNotIn('status', ['cancelled', 'archived'])->exists(),
                422, 'An active Project must be created from the approved Handover before Delivery can begin.');
        }
        $prefix = ['contracts'=>'CON','handovers'=>'HO','deliveries'=>'DEL','invoices'=>'INV'][$next];
        $profile = $this->conversionProfile($document, $next);
        $mapping = $profile['mapping'];
        $overrides = collect($request->input('overrides', []))->only(array_keys($mapping))->filter(fn ($value) => $value !== null && $value !== '')->all();
        $final = array_merge($mapping, $overrides);
        $missing = collect($profile['required'])->filter(fn ($field) => blank($final[$field] ?? null))->values();
        abort_if($missing->isNotEmpty(), 422, 'Complete all required target fields before creating the draft: '.$missing->map(fn ($field) => str_replace('_', ' ', $field))->implode(', ').'.');
        foreach (['account_id' => 'accounts', 'contact_id' => 'contacts', 'deal_id' => 'deals', 'project_id' => 'projects', 'salesperson_id' => 'users', 'project_manager_id' => 'users', 'reviewer_id' => 'users', 'delivery_manager_id' => 'users', 'completion_owner_id' => 'users'] as $field => $table) {
            if (filled($final[$field] ?? null)) abort_unless(\DB::table($table)->where('id', $final[$field])->where('business_id', $document->business_id)->exists(), 422, "Invalid {$field} for this business.");
        }
        $columns = ['account_id', 'contact_id', 'deal_id', 'project_id'];
        $created = OperationalDocument::firstOrCreate(['business_id'=>$document->business_id,'parent_id'=>$document->id,'type'=>$next], ['reference_number'=>$prefix.'-'.$document->reference_number,'account_id'=>$final['account_id']??null,'contact_id'=>$final['contact_id']??null,'deal_id'=>$final['deal_id']??null,'project_id'=>$final['project_id']??null,'owner_id'=>$document->owner_id,'status'=>'draft','details'=>\Illuminate\Support\Arr::except($final, $columns)]);
        foreach($overrides as $field=>$value)if(($mapping[$field]??null)!=$value)\DB::table('conversion_override_audits')->insert(['business_id'=>$document->business_id,'source_document_id'=>$document->id,'target_document_id'=>$created->id,'user_id'=>$request->user()->id,'field'=>$field,'old_value'=>$mapping[$field]??null,'new_value'=>$value,'created_at'=>now(),'updated_at'=>now()]);
        if ($next === 'invoices' && ! $created->trade_document_id && $created->deal_id) {
            $invoice = TradeDocument::create(['business_id'=>$created->business_id,'deal_id'=>$created->deal_id,'created_by'=>$request->user()->id,'type'=>'invoice','document_number'=>$created->reference_number,'status'=>'draft','currency'=>$final['currency'],'subtotal'=>$final['subtotal'],'discount'=>0,'tax'=>0,'total'=>$final['total_amount'],'issue_date'=>$final['invoice_date'],'due_date'=>$final['due_date'],'notes'=>$final['products_services']]);
            $invoice->lines()->create(['description'=>$final['products_services'],'quantity'=>1,'unit_price'=>$final['total_amount'],'line_total'=>$final['total_amount']]);
            $created->update(['trade_document_id'=>$invoice->id]);
        }
        $document->histories()->create(['user_id'=>$request->user()->id,'action'=>'next_document_created','from_status'=>$document->status,'to_status'=>$document->status,'comment'=>"Created {$next} #{$created->id}"]);
        return redirect()->route('operational-documents.index',$next)->with('success', 'Next workflow document created as draft. Complete its mandatory fields before approval.');
    }

    public function previewNext(Request $request, OperationalDocument $document)
    {
        abort_unless($document->business_id===$request->user()->business_id,403);$next=['sales-orders'=>'contracts','contracts'=>'handovers','handovers'=>'deliveries','deliveries'=>'invoices'][$document->type]??null;abort_unless($next,422);$profile=$this->conversionProfile($document,$next);$mapping=$profile['mapping'];$required=$profile['required'];$fieldKinds=$profile['fieldKinds'];return view('operational-documents.conversion-preview',compact('document','next','mapping','required','fieldKinds'));
    }

    private function assertTransitionRequirements(OperationalDocument $document, string $targetStatus): void
    {
        if ($document->type === 'sales-orders' && $targetStatus === 'approved') {
            abort_unless($document->trade_document_id, 422, 'An approved Sales Order must be created from an accepted quotation.');
            $quote = TradeDocument::whereKey($document->trade_document_id)->where('business_id', $document->business_id)->first();
            abort_unless($quote?->type === 'quotation' && $quote->status === 'accepted', 422, 'The source quotation must remain customer accepted.');
            $this->requireDetails($document, ['quotation_number', 'payment_terms', 'delivery_terms', 'billing_address', 'delivery_address', 'products_services', 'subtotal', 'discount_amount', 'tax_amount', 'other_charges', 'grand_total', 'notes', 'terms_conditions', 'attachment_reference', 'expected_delivery_date']);
        }

        if ($document->type === 'contracts' && in_array($targetStatus, ['internal_review', 'approved'], true)) {
            $order = $document->parent;
            abort_unless($order?->type === 'sales-orders' && $order->status === 'approved', 422, 'A Contract must be created from an approved Sales Order.');
            $this->requireDetails($document, ['contract_name', 'contract_type', 'start_date', 'end_date', 'contract_value', 'billing_cycle', 'renewal_type', 'notice_period_days', 'payment_terms', 'deliverables', 'sla_reference', 'scope_of_work', 'terms_conditions', 'contract_document', 'attachment_reference']);
        }

        if ($document->type === 'contracts' && $targetStatus === 'active') {
            abort(422, 'Record the customer and company signatures to activate a Contract.');
        }

        if ($document->type === 'handovers' && in_array($targetStatus, ['pending', 'approved'], true)) {
            $contract = $document->parent;
            abort_unless($contract?->type === 'contracts' && $contract->status === 'active', 422, 'A Handover must be created from an active signed Contract.');
            $this->requireDetails($document, [
                'project_name', 'contract_number', 'salesperson_id', 'project_manager_id', 'reviewer_id', 'project_team', 'project_type', 'project_start_date', 'project_end_date', 'project_value', 'payment_terms', 'scope_of_work',
                'requirements', 'products_services', 'modules_features', 'technology_stack', 'milestones', 'deliverables', 'client_instructions', 'handover_checklist', 'attachment_reference',
            ]);
        }

        if ($document->type === 'deliveries' && in_array($targetStatus, ['ready_for_delivery', 'in_progress'], true)) {
            abort_unless($document->parent?->type === 'handovers' && $document->parent->status === 'approved', 422, 'Delivery must be created from an approved Handover.');
            abort_unless($document->project_id && Project::whereKey($document->project_id)
                ->where('business_id', $document->business_id)->whereNotIn('status', ['cancelled', 'archived'])->exists(),
                422, 'Delivery requires an active linked Project.');
            $this->requireDetails($document, $this->deliveryRequiredFields($targetStatus));
        }

        if ($document->type === 'deliveries' && in_array($targetStatus, ['customer_sign_off', 'closed'], true)) {
            abort_unless(!\DB::table('delivery_corrective_actions')->where('delivery_id',$document->id)->where('status','!=','completed')->exists(),422,'Complete all delivery corrective actions before customer sign-off.');
            $this->requireDetails($document, $this->deliveryRequiredFields($targetStatus));
        }

        if ($document->type === 'deliveries' && $targetStatus === 'closed') {
            $hasUnpaidInvoice = OperationalDocument::where('business_id', $document->business_id)->where('type', 'invoices')
                ->where('parent_id', $document->id)->whereNotIn('status', ['paid', 'closed', 'cancelled'])->exists();
            abort_unless(! $hasUnpaidInvoice, 422, 'Delivery cannot close while a linked invoice remains unpaid. Record and verify payment first.');
        }

        if ($document->type === 'invoices' && $targetStatus === 'pending_approval') {
            abort_unless($document->parent?->type === 'deliveries' && $document->parent->status === 'customer_sign_off', 422, 'An Invoice must be created from a customer-signed-off Delivery.');
            abort_unless($document->trade_document_id && TradeDocument::whereKey($document->trade_document_id)
                ->where('business_id', $document->business_id)->where('type', 'invoice')->exists(), 422, 'The invoice must have a linked financial invoice document.');
            $this->requireDetails($document, ['invoice_date', 'due_date', 'contact_id', 'sales_order_reference', 'contract_reference', 'project_id', 'delivery_reference', 'milestone_reference', 'billing_address', 'invoice_type', 'currency', 'payment_terms', 'products_services', 'subtotal', 'discount_amount', 'tax_amount', 'other_charges', 'total_amount', 'attachment_reference', 'payment_status']);
        }
    }

    private function requireDetails(OperationalDocument $document, array $fields): void
    {
        $details = $document->details ?? [];
        foreach ($fields as $field) {
            $value = array_key_exists($field, $details) ? $details[$field] : $document->{$field};
            abort_unless(filled($value), 422, "Complete {$field} before this transition.");
        }
    }

    private function requireArrayDetails(array $details, array $fields): void
    {
        foreach ($fields as $field) abort_unless(isset($details[$field]) && filled($details[$field]), 422, "Complete {$field} before this status.");
    }

    private function deliveryRequiredFields(string $status): array
    {
        $planning = ['delivery_name','account_id','contact_id','sales_order_reference','project_id','delivery_type','delivery_manager_id','delivery_team','version_release','environment','handover_document','planned_delivery_date','deliverables'];
        if (in_array($status, ['ready_for_delivery','in_progress','internal_qa','uat','customer_approval','deployment','go_live','delivered','customer_sign_off','closed'], true)) {
            $planning = array_merge($planning, ['progress','deployment_details','installation_details','uat_status','approval_status']);
        }
        if (in_array($status, ['customer_approval','deployment','go_live','delivered','customer_sign_off','closed'], true)) {
            $planning = array_merge($planning, ['uat_evidence_reference','release_notes','issues_exceptions']);
        }
        if (in_array($status, ['customer_sign_off','closed'], true)) {
            $planning = array_merge($planning, ['customer_sign_off_reference','completion_owner_id','completion_date','actual_delivery_date']);
        }
        return array_values(array_unique($planning));
    }

    private function salesOrderReference(OperationalDocument $document): ?string
    {
        $current = $document;
        while ($current->parent) {
            $current = $current->parent;
            if ($current->type === 'sales-orders') return $current->reference_number;
        }
        return $document->details['sales_order_reference'] ?? null;
    }

    private function syncTradeInvoiceStatus(OperationalDocument $invoice, string $status): void
    {
        if (! $invoice->trade_document_id) return;
        $document = TradeDocument::whereKey($invoice->trade_document_id)
            ->where('business_id', $invoice->business_id)->where('type', 'invoice')->first();
        if (! $document) return;

        $statusMap = ['pending_approval' => 'pending_approval', 'approved' => 'approved', 'sent' => 'sent'];
        $target = $statusMap[$status] ?? null;
        if ($target && $document->status !== $target) $document->update(['status' => $target]);
    }

    private function createProject(OperationalDocument $handover, Request $request): void
    {
        $details = $handover->details;
        $project = Project::firstOrCreate(['business_id'=>$handover->business_id,'name'=>$details['project_name']], [
            'account_id'=>$handover->account_id,'deal_id'=>$handover->deal_id,'owner_id'=>$handover->owner_id,
            'handover_document_id'=>$handover->id,'project_manager_id'=>$details['project_manager_id'] ?? $handover->owner_id,
            'project_type'=>$details['project_type'] ?? null,'priority'=>'medium','due_date'=>$details['project_end_date'] ?? null,
            'budget'=>$details['project_value'] ?? null,'contract_value'=>$details['project_value'] ?? null,'billing_type'=>'project',
            'technology_stack'=>$details['technology_stack'] ?? null,'scope_of_work'=>$details['scope_of_work'] ?? null,
            'requirements'=>$details['requirements'] ?? null,'deliverables'=>$details['deliverables'] ?? null,
            'description'=>implode("\n\n", [
                'Handover: '.$handover->reference_number,
                'Scope of work: '.($details['scope_of_work'] ?? ''),
                'Requirements: '.($details['requirements'] ?? ''),
                'Products / services: '.($details['products_services'] ?? ''),
                'Handover checklist: '.($details['handover_checklist'] ?? ''),
            ]),'status'=>'planned','start_date'=>$details['project_start_date'] ?? now()->toDateString(),'progress'=>0,
        ]);
        $handover->update(['project_id'=>$project->id]);
        $handover->histories()->create(['user_id'=>$request->user()->id,'action'=>'project_created','from_status'=>'approved','to_status'=>'approved','comment'=>'Project #'.$project->id.' created from approved handover.']);
        $this->notify($handover, 'Project created from approved handover', $request);
    }

    /** Open one support case at customer sign-off so delivery context cannot be lost before support begins. */
    private function createSupportHandoff(OperationalDocument $delivery, Request $request): void
    {
        $subject = 'Delivery handoff: '.$delivery->reference_number;
        $case = CrmCase::where('business_id', $delivery->business_id)->where('subject', $subject)->first();
        if ($case) return;

        $details = $delivery->details ?? [];
        $assignee = $details['completion_owner_id'] ?? $details['delivery_manager_id'] ?? $delivery->owner_id;
        $case = CrmCase::create([
            'business_id' => $delivery->business_id, 'case_number' => app(CaseNumberService::class)->next($delivery->business_id),
            'subject' => $subject, 'account_id' => $delivery->account_id, 'contact_id' => $delivery->contact_id,
            'deal_id' => $delivery->deal_id, 'assigned_to' => $assignee, 'priority' => 'medium', 'status' => 'new',
            'category' => 'support_handoff', 'due_at' => now()->addDay(),
            'description' => 'Created automatically after customer sign-off for delivery '.$delivery->reference_number.".\n\nDeliverables: ".($details['deliverables'] ?? 'Not recorded')."\nRelease notes: ".($details['release_notes'] ?? 'Not recorded'),
        ]);
        $delivery->histories()->create(['user_id' => $request->user()->id, 'action' => 'support_handoff_created', 'from_status' => 'customer_sign_off', 'to_status' => 'customer_sign_off', 'comment' => 'Support case '.$case->case_number.' assigned for post-delivery handoff.']);
        $recipients = User::where('business_id', $delivery->business_id)->where(fn ($q) => $q->whereKey($assignee)->orWhere('is_admin', true))->get();
        app(CrmNotificationService::class)->send($recipients, 'delivery_support_handoff', 'Delivery support handoff', 'Case '.$case->case_number.' was created from customer-signed delivery '.$delivery->reference_number.'.', route('cases.show', $case), CrmCase::class, $case->id, 'new');
    }

    private function notify(OperationalDocument $document, string $message, Request $request): void
    {
        $recipients = User::where('business_id',$document->business_id)->where(fn($q)=>$q->whereKey($document->owner_id)->orWhere('is_admin', true))->get();
        app(CrmNotificationService::class)->send($recipients, 'operational_workflow', 'Operational workflow update', $message,
            route('operational-documents.index',$document->type), 'OperationalDocument', $document->id, $document->status);
        if (in_array($document->type, ['sales-orders','contracts','deliveries','invoices'], true) && $document->contact_id) {
            $email = ContactEmail::where('contact_id',$document->contact_id)->value('email');
            if ($email) try { Mail::raw("CRM update for {$document->reference_number}: {$message}", fn($mail) => $mail->to($email)->subject('CRM update: '.$document->reference_number)); } catch (\Throwable $exception) { report($exception); }
        }
    }
}
