<?php

namespace App\Services;

use App\Models\StatutoryMaster;
use App\Models\StatutoryActDueDate;
use Illuminate\Support\Facades\DB;

class StatutoryDueDateService
{
    /**
     * Entry point – process all statutory_master records
     */
    public function processAll(): void
    {
        StatutoryMaster::where('is_deleted', 0)
            ->where('is_active', 1)
            ->chunk(100, function ($records) {
                foreach ($records as $record) {
                    $this->processSingle($record);
                }
            });
    }

    /**
     * Process one statutory_master row
     */
    private function processSingle(StatutoryMaster $statutory): void
    {
        $periodicity = trim($statutory->periodicity);
        $raw = trim((string) $statutory->due_date_raw);

        // ❌ Skip One-time or Not Applicable
        if (
            strtolower($periodicity) === 'one-time' ||
            empty($raw) ||
            stripos($raw, 'not applicable') !== false
        ) {
            return;
        }

        $dates = [];

        switch (strtolower($periodicity)) {

            case 'monthly':
                $dates = $this->parseMonthly($raw);
                break;

            case 'quarterly':
                $dates = $this->parseMultipleDates($raw, 4);
                break;

            case 'half yearly':
                $dates = $this->parseMultipleDates($raw, 2);
                break;

            case 'annual':
                $date = $this->parseSingleDate($raw);
                if ($date) {
                    $dates[] = $date;
                }
                break;

            default:
                return;
        }

        foreach ($dates as $date) {
            $this->insertIfNotExists($statutory->id, $periodicity, $date);
        }
    }

    /**
     * Monthly parser (e.g. "10th of every month")
     */
    private function parseMonthly(string $raw): array
    {
        if (!preg_match('/(\d{1,2})(st|nd|rd|th)?\s+of\s+every\s+month/i', $raw, $m)) {
            return [];
        }

        $day = (int) $m[1];
        $dates = [];

        for ($month = 1; $month <= 12; $month++) {
            if (checkdate($month, $day, 2000)) {
                $dates[] = sprintf('2000-%02d-%02d', $month, $day);
            }
        }

        return $dates;
    }

    /**
     * Quarterly / Half-Yearly parser
     */
    private function parseMultipleDates(string $raw, int $expectedCount): array
    {
        $parts = array_filter(array_map('trim', explode(',', $raw)));
        if (count($parts) !== $expectedCount) {
            return [];
        }

        $dates = [];

        foreach ($parts as $part) {
            $date = $this->parseSingleDate($part);
            if ($date) {
                $dates[] = $date;
            }
        }

        return count($dates) === $expectedCount ? $dates : [];
    }

    /**
     * Annual parser (e.g. "31st January", "15th of February")
     */
    private function parseSingleDate(string $text): ?string
    {
        $text = trim($text);

        if (!preg_match(
            '/(\d{1,2})(st|nd|rd|th)?\s*(of)?\s*(January|February|March|April|May|June|July|August|September|October|November|December)/i',
            $text,
            $m
        )) {
            return null;
        }

        $day = (int) $m[1];
        $month = date('n', strtotime($m[4]));

        if (!checkdate($month, $day, 2000)) {
            return null;
        }

        return sprintf('2000-%02d-%02d', $month, $day);
    }

    /**
     * Insert safely (no duplicates)
     */
    private function insertIfNotExists(int $actId, string $periodicity, string $date): void
    {
        $exists = StatutoryActDueDate::where('act_id', $actId)
            ->where('periodicity', $periodicity)
            ->where('due_date', $date)
            ->exists();

        if ($exists) {
            return;
        }

        StatutoryActDueDate::create([
            'act_id'      => $actId,
            'periodicity' => $periodicity,
            'due_date'    => $date
        ]);
    }
}
