<?php

namespace App\Models\Tenants;

use App\Models\Members\User;
use App\Traits\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * 근태 기록 모델
 *
 * @property int $id
 * @property int $tenant_id
 * @property int $user_id
 * @property string $base_date
 * @property string $status
 * @property array|null $json_details
 * @property string|null $remarks
 * @property int|null $created_by
 * @property int|null $updated_by
 * @property int|null $deleted_by
 */
class Attendance extends Model
{
    use BelongsToTenant, SoftDeletes;

    protected $table = 'attendances';

    protected $casts = [
        'json_details' => 'array',
        'base_date' => 'date',
    ];

    protected $fillable = [
        'tenant_id',
        'user_id',
        'base_date',
        'status',
        'json_details',
        'remarks',
        'created_by',
        'updated_by',
        'deleted_by',
    ];

    /**
     * JSON 응답에 포함할 accessor
     */
    protected $appends = [
        'check_in',
        'check_out',
        'break_minutes',
    ];

    /**
     * 기본값 설정
     */
    protected $attributes = [
        'status' => 'onTime',
    ];

    // =========================================================================
    // 관계 정의
    // =========================================================================

    /**
     * 사용자 관계
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    /**
     * 생성자 관계
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * 수정자 관계
     */
    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    // =========================================================================
    // json_details 헬퍼 메서드 (Accessor)
    // =========================================================================

    /**
     * 출근 시간 (가장 빠른 출근)
     * check_ins 배열이 있으면 가장 빠른 시간 반환, 없으면 레거시 check_in 사용
     */
    public function getCheckInAttribute(): ?string
    {
        $checkIns = $this->json_details['check_ins'] ?? [];

        if (! empty($checkIns)) {
            $times = array_filter(array_map(fn ($entry) => $entry['time'] ?? null, $checkIns));
            if (! empty($times)) {
                sort($times);

                return $times[0];
            }
        }

        // 레거시 호환: 기존 check_in 필드
        return $this->json_details['check_in'] ?? null;
    }

    /**
     * 퇴근 시간 (가장 늦은 퇴근)
     * check_outs 배열이 있으면 가장 늦은 시간 반환, 없으면 레거시 check_out 사용
     */
    public function getCheckOutAttribute(): ?string
    {
        $checkOuts = $this->json_details['check_outs'] ?? [];

        if (! empty($checkOuts)) {
            $times = array_filter(array_map(fn ($entry) => $entry['time'] ?? null, $checkOuts));
            if (! empty($times)) {
                rsort($times);

                return $times[0];
            }
        }

        // 레거시 호환: 기존 check_out 필드
        return $this->json_details['check_out'] ?? null;
    }

    /**
     * GPS 데이터
     */
    public function getGpsDataAttribute(): ?array
    {
        return $this->json_details['gps_data'] ?? null;
    }

    /**
     * 외근 정보
     */
    public function getExternalWorkAttribute(): ?array
    {
        return $this->json_details['external_work'] ?? null;
    }

    /**
     * 다중 출퇴근 기록 (여러 번 출퇴근)
     */
    public function getMultipleEntriesAttribute(): ?array
    {
        return $this->json_details['multiple_entries'] ?? null;
    }

    /**
     * 근무 시간 (분 단위)
     */
    public function getWorkMinutesAttribute(): ?int
    {
        return isset($this->json_details['work_minutes'])
            ? (int) $this->json_details['work_minutes']
            : null;
    }

    /**
     * 휴게 시간 (분 단위)
ㅣ     * 1. json_details에 저장된 값이 있으면 반환
     * 2. 없으면 check_in/check_out 기준으로 WorkSetting에서 실시간 계산
     */
    public function getBreakMinutesAttribute(): ?int
    {
        // 1. 이미 계산된 값이 있으면 사용
        if (isset($this->json_details['break_minutes'])) {
            return (int) $this->json_details['break_minutes'];
        }

        // 2. 레거시 데이터: check_in, check_out이 있으면 실시간 계산
        $checkIn = $this->check_in;
        $checkOut = $this->check_out;

        if (! $checkIn || ! $checkOut) {
            return null;
        }

        // WorkSetting에서 휴게시간 설정 조회
        $workSetting = WorkSetting::where('tenant_id', $this->tenant_id)->first();

        if (! $workSetting || ! $workSetting->break_start || ! $workSetting->break_end) {
            return null;
        }

        try {
            $checkInCarbon = \Carbon\Carbon::createFromFormat('H:i:s', $checkIn);
            $checkOutCarbon = \Carbon\Carbon::createFromFormat('H:i:s', $checkOut);
            $breakStart = \Carbon\Carbon::createFromFormat('H:i:s', $workSetting->break_start);
            $breakEnd = \Carbon\Carbon::createFromFormat('H:i:s', $workSetting->break_end);

            // 출근~퇴근 시간이 휴게시간을 포함하면 휴게시간 적용
            if ($checkInCarbon->lte($breakStart) && $checkOutCarbon->gte($breakEnd)) {
                return (int) $breakStart->diffInMinutes($breakEnd);
            }
        } catch (\Exception $e) {
            return null;
        }

        return null;
    }

    /**
     * 초과 근무 시간 (분 단위)
     */
    public function getOvertimeMinutesAttribute(): ?int
    {
        return isset($this->json_details['overtime_minutes'])
            ? (int) $this->json_details['overtime_minutes']
            : null;
    }

    /**
     * 지각 시간 (분 단위)
     */
    public function getLateMinutesAttribute(): ?int
    {
        return isset($this->json_details['late_minutes'])
            ? (int) $this->json_details['late_minutes']
            : null;
    }

    /**
     * 조퇴 시간 (분 단위)
     */
    public function getEarlyLeaveMinutesAttribute(): ?int
    {
        return isset($this->json_details['early_leave_minutes'])
            ? (int) $this->json_details['early_leave_minutes']
            : null;
    }

    /**
     * 휴가 유형 (vacation 상태일 때)
     */
    public function getVacationTypeAttribute(): ?string
    {
        return $this->json_details['vacation_type'] ?? null;
    }

    // =========================================================================
    // json_details 업데이트 메서드
    // =========================================================================

    /**
     * json_details에서 특정 키 값 설정
     */
    public function setJsonDetailsValue(string $key, mixed $value): void
    {
        $jsonDetails = $this->json_details ?? [];
        if ($value === null) {
            unset($jsonDetails[$key]);
        } else {
            $jsonDetails[$key] = $value;
        }
        $this->json_details = $jsonDetails;
    }

    /**
     * json_details에서 특정 키 값 가져오기
     */
    public function getJsonDetailsValue(string $key, mixed $default = null): mixed
    {
        return $this->json_details[$key] ?? $default;
    }

    /**
     * 출퇴근 정보 일괄 업데이트
     */
    public function updateAttendanceDetails(array $data): void
    {
        $jsonDetails = $this->json_details ?? [];
        $allowedKeys = [
            'check_in',
            'check_out',
            'gps_data',
            'external_work',
            'multiple_entries',
            'work_minutes',
            'overtime_minutes',
            'late_minutes',
            'early_leave_minutes',
            'vacation_type',
        ];

        foreach ($allowedKeys as $key) {
            if (array_key_exists($key, $data)) {
                if ($data[$key] === null) {
                    unset($jsonDetails[$key]);
                } else {
                    $jsonDetails[$key] = $data[$key];
                }
            }
        }

        $this->json_details = $jsonDetails;
    }

    // =========================================================================
    // 스코프
    // =========================================================================

    /**
     * 특정 날짜의 근태 조회
     */
    public function scopeOnDate($query, string $date)
    {
        return $query->whereDate('base_date', $date);
    }

    /**
     * 특정 기간의 근태 조회
     */
    public function scopeBetweenDates($query, string $startDate, string $endDate)
    {
        return $query->whereBetween('base_date', [$startDate, $endDate]);
    }

    /**
     * 특정 사용자의 근태 조회
     */
    public function scopeForUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

    /**
     * 특정 상태의 근태 조회
     */
    public function scopeWithStatus($query, string $status)
    {
        return $query->where('status', $status);
    }
}
