<?php

namespace App\Http\Controllers\Modules\MasterData;

use App\Http\Controllers\Controller;
use App\Http\Traits\HasRoleViews;
use App\Models\CustomerVendor;
use App\Models\ContactPerson;
use App\Models\CompanyType;
use App\Models\AccountType;
use App\Services\MasterData\CustomerVendorService;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use PhpOffice\PhpSpreadsheet\IOFactory;

/**
 * Unified CustomerVendor Controller
 *
 * Handles customer and vendor management for all roles.
 * Views are automatically resolved based on the logged-in user's role.
 */
class CustomerVendorController extends Controller
{
    use HasRoleViews;

    protected CustomerVendorService $customerVendorService;

    public function __construct(CustomerVendorService $customerVendorService)
    {
        $this->customerVendorService = $customerVendorService;
    }

    /**
     * Display the add customer form
     */
    public function create()
    {
        $companyTypes = CompanyType::orderBy('companytype')->get();
        $accountTypes = AccountType::all();
        return $this->roleView('customer.addcustomer', compact('companyTypes', 'accountTypes'));
    }

    /**
     * Display the customer list page
     */
    public function index()
    {
        $customers = $this->customerVendorService->getAllWithContacts();
        $columns = [
            'Company ID', 'Image', 'Company Name', 'Company Acronym', 'Company Email',
            'Official Contact Number', 'secondary_mobile', 'Company Type', 'GST', 'PAN',
            'MSME/Udyam', 'IEC', 'Website', 'Billing address', 'Shipping address',
            'Bank Name', 'Bank Branch Name', 'Account Number', 'Account Type',
            'Account Holder Name', 'Account Currency', 'IFSC Code', 'SWIFT/BIC Code',
            'Contact Person Name', 'Contact Person Email', 'Contact Person Mobile',
            'Contact Person Designation', 'Status',
        ];
        return $this->roleView('customer.customerlist', compact('customers', 'columns'));
    }

    /**
     * Get all customers for AJAX
     */
    public function getAllCustomers(): JsonResponse
    {
        $customers = $this->customerVendorService->getAllWithContacts();
        return response()->json($customers);
    }

    /**
     * Store a newly created customer/vendor
     */
    public function store(Request $request)
    {
        $role = $this->getCurrentRole();
        Log::info("{$role} - Received request data:", $request->all());

        $validator = Validator::make($request->all(), $this->getValidationRules());

        if ($validator->fails()) {
            Log::error("{$role} - Validation failed:", $validator->errors()->toArray());
            return redirect()->back()->withErrors($validator)->withInput();
        }

        // Handle file upload (infrastructure concern stays in controller)
        $logoPath = null;
        if ($request->hasFile('image')) {
            $logoPath = $request->file('image')->storeAs(
                'logos',
                uniqid() . '.' . $request->file('image')->getClientOriginalExtension(),
                'public'
            );
            Log::info("{$role} - Logo uploaded successfully:", ['path' => $logoPath]);
        }

        try {
            // Prepare data array for service
            $data = [
                'company_role' => $request->company_role,
                'company' => $request->company,
                'email' => $request->email,
                'company_nickname' => $request->company_nickname,
                'image' => $logoPath,
                'mobile' => $request->mobile,
                'secondary_mobile' => $request->secondary_mobile,
                'company_type' => $request->company_type,
                'gstno' => $request->gstno,
                'panno' => $request->panno,
                'msmeno' => $request->msmeno,
                'iecno' => $request->iecno,
                'billing_address' => $request->billing_address,
                'shipping_address' => $request->shipping_address,
                'url' => $request->url,
                'bank_name' => $request->bank_name,
                'branch_name' => $request->branch_name,
                'account_number' => $request->account_number,
                'account_type' => $request->account_type,
                'account_holder_name' => $request->account_holder_name,
                'account_currency' => $request->account_currency ?? 'INR',
                'ifsc_code' => $request->ifsc_code,
                'swift_code' => $request->swift_code,
                'status' => 1,
            ];

            // Prepare contacts array for service
            $contacts = $request->has('contacts') ? $request->contacts : [];

            // Use service method for transaction-wrapped creation
            $customerVendor = $this->customerVendorService->createWithContacts($data, $contacts);

            Log::info("{$role} - Customer/Vendor created via service", ['id' => $customerVendor->id]);

            return $this->redirectToRoute('customer.addcustomer')
                ->with('success', 'Registration Successful!');
        } catch (\Exception $e) {
            Log::error("{$role} - Error occurred:", [
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            return redirect()->back()->with('error', 'Something went wrong! ' . $e->getMessage());
        }
    }

    /**
     * Display the specified customer/vendor
     */
    public function show(int $id)
    {
        $customer = $this->customerVendorService->getWithContacts($id);

        if (!$customer) {
            return $this->redirectToRoute('customer.customerlist')
                ->with('error', 'Customer not found.');
        }

        return $this->roleView('customer.customerview', compact('customer'));
    }

    /**
     * Display the edit form for the specified customer/vendor
     */
    public function edit(int $id)
    {
        $customer = $this->customerVendorService->getWithContacts($id);

        if (!$customer) {
            return $this->redirectToRoute('customer.customerlist')
                ->with('error', 'Customer not found.');
        }

        $companyTypes = CompanyType::orderBy('companytype')->get();
        $accountTypes = AccountType::all();

        return $this->roleView('customer.edit', compact('customer', 'companyTypes', 'accountTypes'));
    }

    /**
     * Update the specified customer/vendor
     */
    public function update(Request $request, int $id)
    {
        $customer = $this->customerVendorService->findByIdOrFail($id);

        $request->validate($this->getUpdateValidationRules($id));

        try {
            // Handle file upload (infrastructure concern stays in controller)
            $logoPath = $customer->image; // Keep existing image by default
            if ($request->hasFile('image')) {
                // Delete old image if exists
                if ($customer->image && Storage::disk('public')->exists($customer->image)) {
                    Storage::disk('public')->delete($customer->image);
                }
                $logoPath = $request->file('image')->store('logos', 'public');
            }

            // Prepare data array for service
            $data = [
                'company' => $request->company,
                'company_nickname' => $request->company_nickname,
                'email' => $request->email,
                'mobile' => $request->mobile,
                'secondary_mobile' => $request->secondary_mobile,
                'company_role' => $request->company_role,
                'company_type' => $request->company_type,
                'gstno' => $request->gstno,
                'panno' => $request->panno,
                'msmeno' => $request->msmeno,
                'iecno' => $request->iecno,
                'billing_address' => $request->billing_address,
                'shipping_address' => $request->shipping_address,
                'url' => $request->url,
                'bank_name' => $request->bank_name,
                'branch_name' => $request->branch_name,
                'account_number' => $request->account_number,
                'account_type' => $request->account_type,
                'account_holder_name' => $request->account_holder_name,
                'account_currency' => $request->account_currency ?? 'INR',
                'ifsc_code' => $request->ifsc_code,
                'swift_code' => $request->swift_code,
                'image' => $logoPath,
            ];

            // Prepare contacts array for service
            $contacts = $request->has('contacts') ? $request->contacts : [];

            // Use service method for transaction-wrapped update
            $this->customerVendorService->updateWithContacts($id, $data, $contacts);

            return $this->redirectToRoute('customer.customerlist')
                ->with('success', 'Customer details updated successfully.');
        } catch (\Exception $e) {
            return redirect()->back()->with('error', 'Something went wrong: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified customer/vendor
     */
    public function destroy(int $id): JsonResponse
    {
        $customer = $this->customerVendorService->findById($id);

        if (!$customer) {
            return response()->json(['message' => 'Customer not found'], 404);
        }

        // Handle file cleanup (infrastructure concern stays in controller)
        if ($customer->image && Storage::disk('public')->exists($customer->image)) {
            Storage::disk('public')->delete($customer->image);
        }

        // Use service for deletion (handles contacts via cascade or service logic)
        $this->customerVendorService->delete($id);

        return response()->json(['message' => 'Customer deleted successfully']);
    }

    /**
     * Import customers from Excel file
     */
    public function import(Request $request)
    {
        $request->validate([
            'excel_file' => 'required|file|mimes:xlsx',
        ]);

        $file = $request->file('excel_file');
        try {
            $spreadsheet = IOFactory::load($file->getRealPath());
            $worksheet = $spreadsheet->getActiveSheet();
            $rows = $worksheet->toArray(null, true, true, true);
            $headerRow = array_map('strtolower', array_map('trim', array_values($rows[1])));

            $expectedHeaders = $this->getImportHeaders();

            if ($headerRow !== $expectedHeaders) {
                Log::error('Bulk customer import: header mismatch.', [
                    'provided' => $headerRow,
                    'expected' => $expectedHeaders,
                ]);
                return back()->with('error', 'Invalid template format. Please use the provided sample template.');
            }

            $successCount = 0;
            $errorCount = 0;
            $errorRows = [];
            DB::beginTransaction();

            foreach (array_slice($rows, 1) as $index => $row) {
                if ($index == 0) continue;

                $rowData = array_combine($expectedHeaders, array_map('trim', array_values($row)));
                $rowData['status'] = ($rowData['status'] === '1' || strtolower($rowData['status']) === 'active') ? 1 : 0;
                $rowData['account_currency'] = $rowData['account_currency'] ?: 'INR';

                $validator = Validator::make($rowData, $this->getImportValidationRules());

                if ($validator->fails()) {
                    $errorCount++;
                    $errorRows[] = "Row " . ($index + 1) . ": " . implode('; ', $validator->errors()->all());
                    continue;
                }

                try {
                    $customer = CustomerVendor::create([
                        'company_role' => $rowData['company_role'],
                        'company' => $rowData['company'],
                        'company_nickname' => $rowData['company_nickname'],
                        'email' => $rowData['email'],
                        'mobile' => $rowData['mobile'],
                        'secondary_mobile' => $rowData['secondary_mobile'],
                        'company_type' => $rowData['company_type'],
                        'gstno' => $rowData['gstno'],
                        'panno' => $rowData['panno'],
                        'msmeno' => $rowData['msmeno'],
                        'iecno' => $rowData['iecno'],
                        'billing_address' => $rowData['billing_address'],
                        'shipping_address' => $rowData['shipping_address'],
                        'url' => $rowData['url'],
                        'bank_name' => $rowData['bank_name'],
                        'branch_name' => $rowData['branch_name'],
                        'account_number' => $rowData['account_number'],
                        'account_type' => $rowData['account_type'],
                        'account_holder_name' => $rowData['account_holder_name'],
                        'account_currency' => $rowData['account_currency'],
                        'ifsc_code' => $rowData['ifsc_code'],
                        'swift_code' => $rowData['swift_code'],
                        'status' => $rowData['status'],
                    ]);

                    for ($i = 1; $i <= 5; $i++) {
                        if (!empty($rowData["contact_name_$i"]) && !empty($rowData["contact_email_$i"]) && !empty($rowData["contact_mobile_$i"])) {
                            ContactPerson::create([
                                'customer_vendor_id' => $customer->id,
                                'name' => $rowData["contact_name_$i"],
                                'email' => $rowData["contact_email_$i"],
                                'mobile' => $rowData["contact_mobile_$i"],
                                'designation' => $rowData["contact_designation_$i"],
                            ]);
                        }
                    }
                    $successCount++;
                } catch (\Exception $e) {
                    $errorCount++;
                    $errorRows[] = "Row " . ($index + 1) . ": " . $e->getMessage();
                    Log::error('Bulk customer import: DB insert failed.', [
                        'row_number' => $index + 1,
                        'exception' => $e->getMessage(),
                        'data' => $rowData,
                    ]);
                }
            }
            DB::commit();

            $message = "{$successCount} customers/vendors imported.";
            if ($errorCount > 0) {
                $message .= " {$errorCount} errors. See below.";
                return back()->with('success', $message)->with('errorRows', $errorRows);
            }
            return back()->with('success', $message);
        } catch (\Exception $e) {
            Log::critical('Bulk customer import failed.', ['exception' => $e->getMessage()]);
            return back()->with('error', 'Failed to import: ' . $e->getMessage());
        }
    }

    /**
     * Get validation rules for store
     */
    protected function getValidationRules(): array
    {
        return [
            // Required: Company Information
            'company_role' => 'required|in:Customer,Vendor,Both',
            'company' => 'required|string|max:255',
            'email' => 'required|email|unique:customer_vendors,email',
            'company_nickname' => 'nullable|string|max:255',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
            'mobile' => 'required|string|max:15',
            'secondary_mobile' => 'nullable|string|max:15',
            'company_type' => 'required|string|max:255',
            'gstno' => 'required|string|max:20|unique:customer_vendors,gstno',
            'panno' => 'required|string|max:10|unique:customer_vendors,panno',
            'msmeno' => 'nullable|string|max:20',
            'iecno' => 'nullable|string|max:20',
            'billing_address' => 'nullable|string|max:500',
            'shipping_address' => 'nullable|string|max:500',
            'url' => 'nullable|url|max:255',
            // Optional: Bank Account Details
            'bank_name' => 'nullable|string|max:255',
            'branch_name' => 'nullable|string|max:255',
            'account_number' => 'nullable|string|max:20',
            'account_type' => 'nullable|string|max:255',
            'account_holder_name' => 'nullable|string|max:255',
            'account_currency' => 'nullable|string|max:10',
            'ifsc_code' => 'nullable|string|max:11',
            'swift_code' => 'nullable|string|max:20',
            // Optional: Contact Persons (only validate if provided)
            'contacts' => 'nullable|array',
            'contacts.*.name' => 'nullable|string|max:255',
            'contacts.*.email' => 'nullable|email|max:255',
            'contacts.*.mobile' => 'nullable|string|max:15',
            'contacts.*.designation' => 'nullable|string|max:255',
        ];
    }

    /**
     * Get validation rules for update
     */
    protected function getUpdateValidationRules(int $id): array
    {
        return [
            // Required: Company Information
            'company' => 'required|string|max:255',
            'company_role' => 'required|in:Customer,Vendor,Both',
            'email' => 'required|email|max:255|unique:customer_vendors,email,' . $id,
            'mobile' => 'required|string|max:15',
            'secondary_mobile' => 'nullable|string|max:15',
            'company_type' => 'required|string|max:255',
            'gstno' => 'required|string|max:20|unique:customer_vendors,gstno,' . $id,
            'panno' => 'required|string|max:10|unique:customer_vendors,panno,' . $id,
            'msmeno' => 'nullable|string|max:20',
            'iecno' => 'nullable|string|max:20',
            'billing_address' => 'nullable|string|max:500',
            'shipping_address' => 'nullable|string|max:500',
            'url' => 'nullable|url|max:255',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
            // Optional: Bank Account Details
            'bank_name' => 'nullable|string|max:255',
            'branch_name' => 'nullable|string|max:255',
            'account_number' => 'nullable|string|max:20',
            'account_type' => 'nullable|string|max:255',
            'account_holder_name' => 'nullable|string|max:255',
            'account_currency' => 'nullable|string|max:10',
            'ifsc_code' => 'nullable|string|max:11',
            'swift_code' => 'nullable|string|max:20',
            // Optional: Contact Persons
            'contacts' => 'nullable|array',
            'contacts.*.name' => 'nullable|string|max:255',
            'contacts.*.email' => 'nullable|email|max:255',
            'contacts.*.mobile' => 'nullable|string|max:15',
            'contacts.*.designation' => 'nullable|string|max:255',
        ];
    }

    /**
     * Get import headers
     */
    protected function getImportHeaders(): array
    {
        return [
            'company_role', 'company', 'company_nickname', 'email', 'mobile', 'secondary_mobile',
            'company_type', 'gstno', 'panno', 'msmeno', 'iecno', 'billing_address', 'shipping_address',
            'url', 'bank_name', 'branch_name', 'account_number', 'account_type', 'account_holder_name',
            'account_currency', 'ifsc_code', 'swift_code', 'status',
            'contact_name_1', 'contact_email_1', 'contact_mobile_1', 'contact_designation_1',
            'contact_name_2', 'contact_email_2', 'contact_mobile_2', 'contact_designation_2',
            'contact_name_3', 'contact_email_3', 'contact_mobile_3', 'contact_designation_3',
            'contact_name_4', 'contact_email_4', 'contact_mobile_4', 'contact_designation_4',
            'contact_name_5', 'contact_email_5', 'contact_mobile_5', 'contact_designation_5',
        ];
    }

    /**
     * Get import validation rules
     */
    protected function getImportValidationRules(): array
    {
        return [
            'company_role' => 'required|in:Customer,Vendor,Both',
            'company' => 'required|string|max:255',
            'email' => 'required|email|unique:customer_vendors,email',
            'mobile' => 'required|digits:10',
            'secondary_mobile' => 'nullable|digits:10',
            'company_type' => 'required|string|max:255',
            'gstno' => 'required|string|max:20|unique:customer_vendors,gstno',
            'panno' => 'required|string|max:10|unique:customer_vendors,panno',
            'bank_name' => 'required|string|max:255',
            'branch_name' => 'required|string|max:255',
            'account_number' => 'required|string|max:20',
            'account_type' => 'required|string|max:255',
            'account_holder_name' => 'required|string|max:255',
            'ifsc_code' => 'required|string|max:11',
        ];
    }
}
