<?php

namespace App\Services\Care\Workflow;

use App\Models\Branch;
use App\Models\FacilityWorkflow;
use App\Models\Organization;
use App\Models\WorkflowStage;
use Illuminate\Support\Facades\DB;

/**
 * Materializes a workflow template from config into a FacilityWorkflow +
 * WorkflowStage graph for an organization. Idempotent per (org, branch):
 * re-installing replaces the workflow's stages with the template definition.
 */
class WorkflowTemplateInstaller
{
    public function __construct(
        protected WorkflowTemplateRegistry $registry,
    ) {}

    /**
     * @param  array{name?: string, category?: string, activate?: bool, replace?: bool}  $options
     */
    public function install(Organization $organization, ?Branch $branch, string $templateKey, array $options = []): FacilityWorkflow
    {
        $template = $this->registry->template($templateKey);
        if ($template === null) {
            throw new \InvalidArgumentException("Unknown workflow template [{$templateKey}].");
        }

        $ownerRef = (string) $organization->owner_ref;
        $activate = (bool) ($options['activate'] ?? true);
        $replace = (bool) ($options['replace'] ?? true);
        $name = (string) ($options['name'] ?? ($template['label'] ?? $templateKey));
        $category = $options['category'] ?? data_get($organization->settings, 'facility_category');

        return DB::transaction(function () use ($organization, $branch, $template, $templateKey, $ownerRef, $activate, $replace, $name, $category) {
            $query = FacilityWorkflow::query()
                ->where('organization_id', $organization->id)
                ->where('branch_id', $branch?->id);

            $workflow = $query->first();

            if ($workflow === null) {
                $workflow = FacilityWorkflow::create([
                    'owner_ref' => $ownerRef,
                    'organization_id' => $organization->id,
                    'branch_id' => $branch?->id,
                    'name' => $name,
                    'template_key' => $templateKey,
                    'category' => $category,
                    'is_active' => $activate,
                    'settings' => ['description' => $template['description'] ?? null],
                ]);
            } else {
                $workflow->forceFill([
                    'name' => $name,
                    'template_key' => $templateKey,
                    'category' => $category,
                    'is_active' => $activate ? true : $workflow->is_active,
                    'settings' => array_merge($workflow->settings ?? [], [
                        'description' => $template['description'] ?? null,
                    ]),
                ])->save();

                if ($replace) {
                    WorkflowStage::query()->where('workflow_id', $workflow->id)->delete();
                }
            }

            if ($replace || $workflow->stages()->count() === 0) {
                $this->syncStages($workflow, $ownerRef, (array) ($template['stages'] ?? []));
            }

            return $workflow->fresh(['stages']) ?? $workflow;
        });
    }

    /**
     * @param  list<array<string, mixed>>  $stages
     */
    protected function syncStages(FacilityWorkflow $workflow, string $ownerRef, array $stages): void
    {
        $order = 0;
        foreach ($stages as $stage) {
            $order += 10;
            WorkflowStage::create([
                'owner_ref' => $ownerRef,
                'workflow_id' => $workflow->id,
                'code' => (string) $stage['code'],
                'name' => (string) ($stage['name'] ?? $stage['code']),
                'type' => (string) ($stage['type'] ?? 'custom'),
                'queue_context' => $stage['queue_context'] ?? null,
                'department_type' => $stage['department_type'] ?? null,
                'sort_order' => $stage['sort_order'] ?? $order,
                'requires_payment' => (bool) ($stage['requires_payment'] ?? false),
                'payment_timing' => (string) ($stage['payment_timing'] ?? 'none'),
                'payment_modes' => $stage['payment_modes'] ?? ['internal_cashier', 'digital'],
                'insurance_eligible' => (bool) ($stage['insurance_eligible'] ?? false),
                'credit_allowed' => (bool) ($stage['credit_allowed'] ?? false),
                'allow_override' => (bool) ($stage['allow_override'] ?? true),
                'charge_code' => $stage['charge_code'] ?? null,
                'charge_label' => $stage['charge_label'] ?? null,
                'default_amount_minor' => $stage['default_amount_minor'] ?? null,
                'default_next' => $stage['default_next'] ?? null,
                'can_return' => (bool) ($stage['can_return'] ?? false),
                'can_skip' => (bool) ($stage['can_skip'] ?? false),
                'optional' => (bool) ($stage['optional'] ?? false),
                'creates_child' => (bool) ($stage['creates_child'] ?? false),
            ]);
        }
    }
}
