<?php

namespace App\Models\Products;

use App\Models\Orders\ClientGroup;
use App\Traits\Auditable;
use App\Traits\BelongsToTenant;
use App\Traits\ModelTrait;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class Price extends Model
{
    use Auditable, BelongsToTenant, ModelTrait, SoftDeletes;

    protected $table = 'prices';

    // ─────────────────────────────────────────────────────────────
    // Constants
    // ─────────────────────────────────────────────────────────────

    // 상태
    public const STATUS_DRAFT = 'draft';

    public const STATUS_ACTIVE = 'active';

    public const STATUS_INACTIVE = 'inactive';

    public const STATUS_FINALIZED = 'finalized';

    // 품목 유형은 common_codes 테이블의 code_group='item_type'에서 관리
    // FG(완제품), PT(부품), RM(원자재), SM(반제품), CS(소모품)

    protected $fillable = [
        'tenant_id',
        'item_type_code',
        'item_id',
        'client_group_id',
        'purchase_price',
        'processing_cost',
        'loss_rate',
        'margin_rate',
        'sales_price',
        'rounding_rule',
        'rounding_unit',
        'supplier',
        'effective_from',
        'effective_to',
        'note',
        'status',
        'is_final',
        'finalized_at',
        'finalized_by',
        'created_by',
        'updated_by',
        'deleted_by',
    ];

    protected $casts = [
        'item_id' => 'integer',
        'client_group_id' => 'integer',
        'purchase_price' => 'decimal:4',
        'processing_cost' => 'decimal:4',
        'loss_rate' => 'decimal:2',
        'margin_rate' => 'decimal:2',
        'sales_price' => 'decimal:4',
        'rounding_unit' => 'integer',
        'effective_from' => 'date',
        'effective_to' => 'date',
        'is_final' => 'boolean',
        'finalized_at' => 'datetime',
        'finalized_by' => 'integer',
        'created_by' => 'integer',
        'updated_by' => 'integer',
        'deleted_by' => 'integer',
    ];

    // ─────────────────────────────────────────────────────────────
    // Relations
    // ─────────────────────────────────────────────────────────────

    /**
     * 고객 그룹 관계
     */
    public function clientGroup(): BelongsTo
    {
        return $this->belongsTo(ClientGroup::class, 'client_group_id');
    }

    /**
     * 리비전 이력
     */
    public function revisions(): HasMany
    {
        return $this->hasMany(PriceRevision::class, 'price_id');
    }

    // ─────────────────────────────────────────────────────────────
    // Scopes
    // ─────────────────────────────────────────────────────────────

    /**
     * 특정 품목 필터
     */
    public function scopeForItem($query, string $itemType, int $itemId)
    {
        return $query->where('item_type_code', $itemType)
            ->where('item_id', $itemId);
    }

    /**
     * 특정 고객그룹 필터
     */
    public function scopeForClientGroup($query, int $clientGroupId)
    {
        return $query->where('client_group_id', $clientGroupId);
    }

    /**
     * 특정 일자에 유효한 단가 필터
     */
    public function scopeValidAt($query, string $date)
    {
        return $query->where('effective_from', '<=', $date)
            ->where(function ($q) use ($date) {
                $q->whereNull('effective_to')
                    ->orWhere('effective_to', '>=', $date);
            });
    }

    /**
     * 활성 상태 단가 필터
     */
    public function scopeActive($query)
    {
        return $query->whereIn('status', ['active', 'finalized']);
    }

    // ─────────────────────────────────────────────────────────────
    // Business Logic
    // ─────────────────────────────────────────────────────────────

    /**
     * 수정 가능 여부 확인
     */
    public function canEdit(): bool
    {
        return ! $this->is_final;
    }

    /**
     * 확정 가능 여부 확인
     */
    public function canFinalize(): bool
    {
        if ($this->is_final) {
            return false;
        }

        // 필수 필드 확인
        if (empty($this->sales_price) && empty($this->purchase_price)) {
            return false;
        }

        return true;
    }

    /**
     * 판매단가 자동 계산
     * 공식: (매입단가 + 가공비) * (1 + LOSS율) * (1 + 마진율)
     */
    public function calculateSalesPrice(): ?float
    {
        $purchasePrice = (float) ($this->purchase_price ?? 0);
        $processingCost = (float) ($this->processing_cost ?? 0);
        $lossRate = (float) ($this->loss_rate ?? 0) / 100;
        $marginRate = (float) ($this->margin_rate ?? 0) / 100;

        if ($purchasePrice <= 0) {
            return null;
        }

        $baseCost = $purchasePrice + $processingCost;
        $withLoss = $baseCost * (1 + $lossRate);
        $withMargin = $withLoss * (1 + $marginRate);

        // 반올림 적용
        return $this->applyRounding($withMargin);
    }

    /**
     * 반올림 규칙 적용
     */
    private function applyRounding(float $value): float
    {
        $unit = $this->rounding_unit ?? 1;
        $rule = $this->rounding_rule ?? 'round';

        if ($unit <= 0) {
            $unit = 1;
        }

        $result = match ($rule) {
            'ceil' => ceil($value / $unit) * $unit,
            'floor' => floor($value / $unit) * $unit,
            default => round($value / $unit) * $unit,
        };

        return (float) $result;
    }

    /**
     * 스냅샷 데이터 생성 (리비전용)
     */
    public function toSnapshot(): array
    {
        return [
            'item_type_code' => $this->item_type_code,
            'item_id' => $this->item_id,
            'client_group_id' => $this->client_group_id,
            'purchase_price' => $this->purchase_price,
            'processing_cost' => $this->processing_cost,
            'loss_rate' => $this->loss_rate,
            'margin_rate' => $this->margin_rate,
            'sales_price' => $this->sales_price,
            'rounding_rule' => $this->rounding_rule,
            'rounding_unit' => $this->rounding_unit,
            'supplier' => $this->supplier,
            'effective_from' => $this->effective_from?->toDateString(),
            'effective_to' => $this->effective_to?->toDateString(),
            'note' => $this->note,
            'status' => $this->status,
            'is_final' => $this->is_final,
        ];
    }

    // ─────────────────────────────────────────────────────────────
    // Static Query Methods (견적 산출용)
    // ─────────────────────────────────────────────────────────────

    /**
     * 특정 품목의 현재 유효 단가 조회
     *
     * @param  int  $tenantId  테넌트 ID
     * @param  string  $itemTypeCode  품목 유형 (PRODUCT/MATERIAL)
     * @param  int  $itemId  품목 ID
     * @param  int|null  $clientGroupId  고객 그룹 ID (NULL = 기본가)
     */
    public static function getCurrentPrice(
        int $tenantId,
        string $itemTypeCode,
        int $itemId,
        ?int $clientGroupId = null
    ): ?self {
        $today = now()->toDateString();

        $query = static::query()
            ->where('tenant_id', $tenantId)
            ->where('item_type_code', $itemTypeCode)
            ->where('item_id', $itemId)
            ->whereIn('status', [self::STATUS_ACTIVE, self::STATUS_FINALIZED])
            ->where('effective_from', '<=', $today)
            ->where(function ($q) use ($today) {
                $q->whereNull('effective_to')
                    ->orWhere('effective_to', '>=', $today);
            });

        // 고객그룹 지정된 가격 우선, 없으면 기본가
        if ($clientGroupId) {
            $groupPrice = (clone $query)
                ->where('client_group_id', $clientGroupId)
                ->orderByDesc('effective_from')
                ->first();

            if ($groupPrice) {
                return $groupPrice;
            }
        }

        // 기본가 (client_group_id = NULL)
        return $query
            ->whereNull('client_group_id')
            ->orderByDesc('effective_from')
            ->first();
    }

    /**
     * 품목 코드로 현재 유효 판매단가 조회
     *
     * @param  int  $tenantId  테넌트 ID
     * @param  string  $itemCode  품목 코드
     * @return float 판매단가 (없으면 0)
     */
    public static function getSalesPriceByItemCode(int $tenantId, string $itemCode): float
    {
        // items 테이블에서 품목 코드로 검색
        $item = \Illuminate\Support\Facades\DB::table('items')
            ->where('tenant_id', $tenantId)
            ->where('code', $itemCode)
            ->whereNull('deleted_at')
            ->first();

        if (! $item) {
            return 0;
        }

        $price = static::getCurrentPrice($tenantId, $item->item_type, $item->id);

        return (float) ($price?->sales_price ?? 0);
    }
}
