<?php

namespace App\Imports;

use App\Models\Account;
use App\Models\JournalEntry;
use App\Models\JournalEntryLine;
use App\Models\Partner;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\ToCollection;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use PhpOffice\PhpSpreadsheet\Shared\Date as ExcelDate;

class BulkJournalEntryImport implements ToCollection, WithHeadingRow
{
    public function collection(Collection $rows)
    {
        if ($rows->isEmpty()) return;

        // Group rows by 'entry_number' or 'reference' or 'date' if entry_number is missing
        // For bulk imports, we most likely want a unique identifier per entry.
        // If 'entry_number' is empty, we can try to use a combination of date and reference.
        $groupedRows = $rows->groupBy(function ($row) {
            $entryNum = trim($row['entry_number'] ?? '');
            if ($entryNum !== '') return 'num_' . $entryNum;
            
            $date = !empty($row['date']) ? $this->parseDate($row['date']) : 'no_date';
            $ref = trim($row['reference'] ?? 'no_ref');
            return $date . '_' . $ref;
        });

        foreach ($groupedRows as $groupKey => $lines) {
            $this->processEntryGroup($lines);
        }
    }

    protected function processEntryGroup(Collection $lines)
    {
        $firstLine = $lines->first();
        
        $date = $this->parseDate($firstLine['date'] ?? null);
        $reference = trim($firstLine['reference'] ?? '');
        $description = trim($firstLine['description'] ?? 'Bulk Import');
        $partnerName = trim($firstLine['partner_name'] ?? '');
        
        $partnerId = null;
        if ($partnerName !== '') {
            $partner = Partner::where('name', 'like', $partnerName)->first();
            if ($partner) {
                $partnerId = $partner->id;
            }
        }

        $totalDebit = $lines->sum(fn($l) => floatval($l['debit'] ?? 0));
        $totalCredit = $lines->sum(fn($l) => floatval($l['credit'] ?? 0));

        // Check for balance (Double Entry rule)
        if (abs($totalDebit - $totalCredit) > 0.01) {
            // Optional: Log error or throw exception? 
            // For now, we skip unbalanced entries to prevent data corruption.
            return;
        }

        DB::transaction(function () use ($date, $reference, $description, $partnerId, $lines) {
            $entry = JournalEntry::create([
                'entry_number' => JournalEntry::generateEntryNumber(),
                'date' => $date,
                'reference' => $reference,
                'description' => $description,
                'partner_id' => $partnerId,
                'branch_id' => auth()->user()->branch_id ?? 1,
                'created_by' => auth()->id(),
                'status' => 'draft',
            ]);

            foreach ($lines as $line) {
                if (empty($line['account_code'])) continue;

                $account = Account::where('code', $line['account_code'])->first();
                if (!$account) continue;

                $debit = floatval($line['debit'] ?? 0);
                $credit = floatval($line['credit'] ?? 0);

                if ($debit == 0 && $credit == 0) continue;

                JournalEntryLine::create([
                    'journal_entry_id' => $entry->id,
                    'account_id' => $account->id,
                    'description' => $line['description'] ?? $description,
                    'debit' => $debit,
                    'credit' => $credit,
                ]);
            }
        });
    }

    protected function parseDate($dateValue)
    {
        if (empty($dateValue)) return now()->format('Y-m-d');

        try {
            if (is_numeric($dateValue)) {
                return ExcelDate::excelToDateTimeObject($dateValue)->format('Y-m-d');
            }
            return Carbon::parse($dateValue)->format('Y-m-d');
        } catch (\Exception $e) {
            return now()->format('Y-m-d');
        }
    }
}
