<?php

namespace Tests\Feature;

use App\Models\Branch;
use App\Models\Business;
use App\Models\Customer;
use App\Models\Loan;
use App\Models\LoanDocument;
use App\Models\LoanProduct;
use App\Models\User;
use Database\Seeders\DatabaseSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
use ZipArchive;

class LoanDocumentReviewTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed(DatabaseSeeder::class);
        Storage::fake('local');
    }

    public function test_pdf_document_opens_inline_for_review(): void
    {
        [$admin, $loan] = $this->fixture('pdf');
        $path = 'loans/'.$loan->id.'/supporting/review.pdf';
        Storage::disk('local')->put($path, '%PDF-1.4 review document');
        $document = LoanDocument::create([
            'loan_id' => $loan->id,
            'kind' => 'supporting',
            'document_type' => 'Identity Document',
            'original_name' => 'customer-review.pdf',
            'file_path' => $path,
            'mime_type' => 'application/pdf',
            'file_size' => 24,
            'uploaded_by' => $admin->id,
        ]);

        $response = $this->actingAs($admin)->get(route('loans.documents.review', [$loan, $document]))->assertOk();

        $response->assertHeader('content-type', 'application/pdf');
        $this->assertStringContainsString('inline', strtolower((string) $response->headers->get('content-disposition')));
        $this->assertStringContainsString('%PDF-1.4', $response->streamedContent());
    }

    public function test_docx_document_has_in_system_readable_review_page(): void
    {
        [$admin, $loan] = $this->fixture('docx');
        $path = 'loans/'.$loan->id.'/generated-contracts/review.docx';
        Storage::disk('local')->put($path, $this->docx('BORROWER CONTRACT REVIEW TEXT'));
        $document = LoanDocument::create([
            'loan_id' => $loan->id,
            'kind' => 'generated_contract',
            'document_type' => 'Generated Loan Contract',
            'original_name' => 'loan-contract.docx',
            'file_path' => $path,
            'mime_type' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'file_size' => Storage::disk('local')->size($path),
            'uploaded_by' => $admin->id,
        ]);

        $this->actingAs($admin)
            ->get(route('loans.documents.review', [$loan, $document]))
            ->assertOk()
            ->assertSee('Review document')
            ->assertSee('BORROWER CONTRACT REVIEW TEXT')
            ->assertSee('Download original');
    }

    public function test_document_cannot_be_reviewed_through_another_loan(): void
    {
        [$admin, $loan] = $this->fixture('scope-a');
        [, $otherLoan] = $this->fixture('scope-b');
        $path = 'loans/'.$loan->id.'/supporting/scoped.pdf';
        Storage::disk('local')->put($path, '%PDF-1.4 scoped');
        $document = LoanDocument::create([
            'loan_id' => $loan->id,
            'kind' => 'supporting',
            'document_type' => 'Scoped Document',
            'original_name' => 'scoped.pdf',
            'file_path' => $path,
            'mime_type' => 'application/pdf',
            'file_size' => 16,
            'uploaded_by' => $admin->id,
        ]);

        $this->actingAs($admin)
            ->get(route('loans.documents.review', [$otherLoan, $document]))
            ->assertNotFound();
    }

    private function fixture(string $tag): array
    {
        $business = Business::firstOrFail();
        $admin = User::where('username', 'admin')->firstOrFail();
        $branch = Branch::create([
            'business_id' => $business->id,
            'name' => 'Review Branch '.str($tag)->headline(),
            'status' => 'active',
        ]);
        $customer = Customer::create([
            'branch_id' => $branch->id,
            'customer_number' => 'CUS-RVW-'.strtoupper(substr(md5($tag), 0, 8)),
            'identity_mode' => 'with_nin',
            'first_name' => 'Asha',
            'last_name' => 'Review',
            'nin' => 'NIN-RVW-'.strtoupper(substr(md5('nin-'.$tag), 0, 8)),
            'phone' => '06'.str_pad((string) (10000000 + Customer::count()), 8, '0', STR_PAD_LEFT),
            'status' => 'active',
            'created_by' => $admin->id,
        ]);
        $product = LoanProduct::create([
            'business_id' => $business->id,
            'name' => 'Review Product '.str($tag)->headline(),
            'minimum_amount' => '100.00',
            'maximum_amount' => '1000000.00',
            'duration' => 1,
            'duration_unit' => 'months',
            'interest_rate' => '10.000000',
            'interest_calculation_method' => 'flat',
            'repayment_frequency' => 'monthly',
            'grace_period_days' => 0,
            'late_payment_penalty_type' => 'none',
            'late_payment_penalty_value' => '0.000000',
            'processing_fee_type' => 'fixed',
            'processing_fee_value' => '0.000000',
            'insurance_fee_type' => 'fixed',
            'insurance_fee_value' => '0.000000',
            'other_charges' => '0.00',
            'collateral_required' => false,
            'guarantor_required' => false,
            'status' => 'active',
        ]);
        $loan = Loan::create([
            'branch_id' => $branch->id,
            'customer_id' => $customer->id,
            'loan_product_id' => $product->id,
            'sequence_number' => Loan::count() + 1,
            'sequence_year' => 2026,
            'loan_number' => 'LN-RVW-'.strtoupper(substr(md5($tag), 0, 8)),
            'principal' => '100000.00',
            'interest' => '10000.00',
            'processing_fee' => '0.00',
            'insurance_fee' => '0.00',
            'other_charges' => '0.00',
            'fees' => '0.00',
            'total_repayment' => '110000.00',
            'principal_outstanding' => '100000.00',
            'interest_outstanding' => '10000.00',
            'fees_outstanding' => '0.00',
            'penalties_outstanding' => '0.00',
            'total_outstanding' => '110000.00',
            'total_paid' => '0.00',
            'purpose' => 'Document review test',
            'schedule_start_date' => '2026-08-13',
            'status' => 'under_review',
            'created_by' => $admin->id,
        ]);

        return [$admin, $loan];
    }

    private function docx(string $text): string
    {
        $temporary = tempnam(sys_get_temp_dir(), 'loan-doc-review-');
        $path = $temporary.'.docx';
        @unlink($temporary);

        $zip = new ZipArchive();
        $this->assertTrue($zip->open($path, ZipArchive::CREATE | ZipArchive::OVERWRITE));
        $zip->addFromString('word/document.xml', '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
            .'<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:body>'
            .'<w:p><w:r><w:t>'.htmlspecialchars($text, ENT_XML1).'</w:t></w:r></w:p>'
            .'</w:body></w:document>');
        $zip->close();

        $content = file_get_contents($path);
        @unlink($path);
        $this->assertIsString($content);

        return $content;
    }
}
