<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;

class WhatsappGroupMembership extends BaseModel
{
    protected $table = 'whatsapp_group_memberships';

    protected $fillable = [
        'class_section_id',
        'school_year',
        'semester',
        'subject_type',
        'subject_id',
        'is_member',
        'verified_by',
        'verified_at',
        'created_at',
        'updated_at',
    ];

    public $timestamps = true; // created_at, updated_at

    protected $casts = [
        'class_section_id' => 'integer',
        'subject_id'       => 'integer',
        'is_member'        => 'boolean',
        'verified_by'      => 'integer',
        'verified_at'      => 'datetime',
        'created_at'       => 'datetime',
        'updated_at'       => 'datetime',
    ];

    /* ============================================================
     * Constants
     * ============================================================
     */
    public const TYPE_PRIMARY = 'primary';
    public const TYPE_SECOND  = 'second';

    public static function normType(string $type): string
    {
        return strtolower(trim($type)) === self::TYPE_SECOND ? self::TYPE_SECOND : self::TYPE_PRIMARY;
    }

    /* ============================================================
     * Scopes
     * ============================================================
     */

    public function scopeForSections(Builder $q, array $sectionIds): Builder
    {
        $ids = array_values(array_unique(array_filter(array_map('intval', $sectionIds))));
        return empty($ids) ? $q->whereRaw('1=0') : $q->whereIn('class_section_id', $ids);
    }

    public function scopeForYear(Builder $q, string $year): Builder
    {
        return $q->where('school_year', trim($year));
    }

    public function scopeForSemester(Builder $q, string $sem): Builder
    {
        $sem = trim($sem);
        return $sem === '' ? $q : $q->where('semester', $sem);
    }

    public function scopeForSubject(Builder $q, string $type, int $subjectId): Builder
    {
        return $q->where('subject_type', static::normType($type))
                 ->where('subject_id', $subjectId);
    }

    /* ============================================================
     * Methods (CI-compatible behavior)
     * ============================================================
     */

    /**
     * Fetch all membership rows for the given sections and term.
     * Returns an associative index ["<sid>:<type>:<id>" => row(array)].
     */
    public static function getBySectionsAndTerm(array $sectionIds, string $year, string $sem): array
    {
        $ids = array_values(array_unique(array_filter(array_map('intval', $sectionIds))));
        if (empty($ids)) return [];

        $year = trim($year);
        $sem  = trim($sem);

        $q = static::query()
            ->forSections($ids)
            ->forYear($year);

        if ($sem !== '') {
            $q->where('semester', $sem);
        }

        // Prefer most recently updated membership when duplicates exist.
        $rows = $q->orderByDesc('updated_at')
            ->orderByDesc('id')
            ->get();

        $out = [];
        foreach ($rows as $m) {
            $k = sprintf('%d:%s:%d', (int)$m->class_section_id, (string)$m->subject_type, (int)$m->subject_id);
            if (!isset($out[$k])) {
                $out[$k] = $m->toArray();
            }
        }

        return $out;
    }

    /**
     * Upsert membership row for a specific subject and class/term.
     * Returns the row ID.
     *
     * Matches CI logic:
     * - Key is (class_section_id, school_year, subject_type, subject_id) plus semester if provided.
     * - If semester is blank, we update most recent row for that key and keep its semester.
     * - If verifiedBy provided, set verified_by + verified_at.
     */
    public static function upsertMembership(
        int $classSectionId,
        string $year,
        string $sem,
        string $type,
        int $subjectId,
        bool $isMember,
        ?int $verifiedBy = null
    ): int {
        $type = static::normType($type);
        $year = trim($year);
        $sem  = trim($sem);

        $payload = [
            'class_section_id' => $classSectionId,
            'school_year'      => $year,
            'semester'         => $sem,
            'subject_type'     => $type,
            'subject_id'       => $subjectId,
            'is_member'        => $isMember ? 1 : 0,
        ];

        if ($verifiedBy) {
            $payload['verified_by'] = $verifiedBy;
            $payload['verified_at'] = now();
        }

        // If semester is provided, we can do a clean updateOrCreate.
        if ($sem !== '') {
            $row = static::query()->updateOrCreate(
                [
                    'class_section_id' => $classSectionId,
                    'school_year'      => $year,
                    'semester'         => $sem,
                    'subject_type'     => $type,
                    'subject_id'       => $subjectId,
                ],
                $payload
            );
            return (int) $row->id;
        }

        // Semester blank => match CI behavior: find most recent row for the key (without semester filter).
        $existing = static::query()
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $year)
            ->where('subject_type', $type)
            ->where('subject_id', $subjectId)
            ->orderByDesc('updated_at')
            ->orderByDesc('id')
            ->first();

        if ($existing) {
            // Keep semester from the existing row if present (CI behavior).
            if (!empty($existing->semester)) {
                $payload['semester'] = (string) $existing->semester;
            }

            $existing->fill($payload);
            $existing->save();

            return (int) $existing->id;
        }

        // No existing row => create a new one (semester remains blank)
        $created = static::query()->create($payload);
        return (int) $created->id;
    }

    /* ============================================================
     * Optional validation helper
     * ============================================================
     */

    public static function rules(bool $updating = false): array
    {
        $req = $updating ? 'sometimes' : 'required';

        return [
            'class_section_id' => [$req, 'integer', 'min:1'],
            'school_year'      => [$req, 'string', 'max:20'],
            'semester'         => ['nullable', 'string', 'max:20'],
            'subject_type'     => [$req, 'string', 'in:' . implode(',', [self::TYPE_PRIMARY, self::TYPE_SECOND])],
            'subject_id'       => [$req, 'integer', 'min:1'],
            'is_member'        => ['nullable', 'boolean'],
            'verified_by'      => ['nullable', 'integer'],
            'verified_at'      => ['nullable', 'date'],
        ];
    }
}