<?php

namespace App\Http\Controllers;

use App\Http\Requests\Contact\StoreContactRequest;
use App\Http\Requests\Contact\UpdateContactRequest;
use App\Models\Business;
use App\Models\Contact;
use App\Models\Shop;
use App\Models\Account;
use App\Models\ChartOfAccount;
use App\Traits\LogsActivity;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Yajra\DataTables\Facades\DataTables;

class ContactController extends Controller
{
    use LogsActivity;
	public function index(Request $request)
	{
		if ($request->ajax()) {
			$query = Contact::query()->select('contacts.*');

			// Apply filters
			if ($request->filled('type')) {
				$query->where('type', $request->type);
			}

			if ($request->filled('gender')) {
				$query->where('gender', $request->gender);
			}

			if ($request->filled('status')) {
				$query->where('is_active', $request->status);
			}

			if ($request->filled('rating')) {
				$query->where('rating', '>=', $request->rating);
			}

			if ($request->filled('search')) {
				$search = $request->search;
				$query->where(function($q) use ($search) {
					$q->where('name', 'like', "%{$search}%")
					  ->orWhere('email', 'like', "%{$search}%")
					  ->orWhere('phone', 'like', "%{$search}%")
					  ->orWhere('cnic', 'like', "%{$search}%")
					  ->orWhere('contact_person', 'like', "%{$search}%");
				});
			}

			return DataTables::of($query)
				->editColumn('cnic', function (Contact $contact) {
					return $contact->formatted_cnic;
				})
				->editColumn('gender', function (Contact $contact) {
					return $contact->gender_label;
				})
				->editColumn('is_active', function (Contact $contact) {
					$options = [
						1 => 'Active',
						0 => 'Inactive'
					];
					$selected = $contact->is_active ? 1 : 0;
					return '<select class="form-select form-select-sm status-select" style="margin-top:-6px;" data-id="'.$contact->id.'" data-url="'.route('contacts.toggle-active', $contact).'">'
						. '<option value="1" '.($selected == 1 ? 'selected' : '').'>Active</option>'
						. '<option value="0" '.($selected == 0 ? 'selected' : '').'>Inactive</option>'
						. '</select>';
				})
				->editColumn('created_at', function (Contact $contact) {
					$business = class_exists(Business::class) ? Business::first() : null;
					$tz = $business && $business->timezone ? $business->timezone : config('app.timezone');
					return $contact->created_at->setTimezone('Asia/Karachi')->format('Y-m-d H:i:s');
				})
				->addColumn('actions', function (Contact $contact) {
					$editUrl = route('contacts.edit', $contact);
					$deleteUrl = route('contacts.destroy', $contact);
					$csrf = csrf_field();
					$method = method_field('DELETE');
					return '<div class="d-flex gap-2">'
						.'<a href="'.$editUrl.'" class="btn btn-sm btn-outline-primary" title="Edit">'
						.'<i class="fas fa-edit me-1"></i>Edit</a>'
						.'<form action="'.$deleteUrl.'" method="POST" style="display: inline;" onsubmit="return confirm(\'Are you sure you want to delete this contact?\')">'
						.$csrf.$method.'<button type="submit" class="btn btn-sm btn-outline-danger" title="Delete">'
						.'<i class="fas fa-trash me-1"></i>Delete</button></form>'
						.'</div>';
				})
				->rawColumns(['actions', 'is_active'])
				->toJson();
		}

		return view('contacts.index', [
			'contactsCount' => Contact::count()
		]);
	}

	public function toggleActive(Request $request, Contact $contact): JsonResponse
	{
		try {
			$newStatus = $request->boolean('is_active');

			DB::transaction(function () use ($contact, $newStatus) {
				// Update contact status
				$contact->update(['is_active' => $newStatus]);

				// Sync user status if contact has an associated user
				if ($contact->user_id && $contact->user) {
					$contact->user->update(['is_active' => $newStatus]);
				}
			});

			$this->logActivity('Contact status toggle', $contact, [
				'action' => 'toggle_active',
				'new_status' => $contact->is_active ? 'active' : 'inactive',
				'user_synced' => $contact->user_id ? true : false
			]);

			return response()->json([
				'success' => true,
				'message' => 'Contact status updated successfully' . ($contact->user_id ? ' (user status also synced)' : ''),
				'is_active' => $contact->is_active
			]);
		} catch (\Exception $e) {
			$this->logError('Contact status toggle', $e, [
				'contact_id' => $contact->id,
				'action' => 'toggle_active'
			]);

			return response()->json([
				'success' => false,
				'message' => 'Failed to update contact status'
			], 500);
		}
	}

	public function create(): View
	{
		$roles = \Spatie\Permission\Models\Role::where('id', '>', 2)->pluck('name', 'id')->toArray();

        $shops = Account::where('model_type', 'shop')->where('is_active', true)->get();
		return view('contacts.create', compact('roles', 'shops'));
	}

	public function store(StoreContactRequest $request): RedirectResponse
	{
        // dd("Ddd");
		try {
			$contact = null;
			$user = null;

			// Validate the data first
			$validatedData = $request->validated();

			// Additional validation for required fields
			$validator = \Illuminate\Support\Facades\Validator::make($validatedData, [
				'cnic' => ['required', 'string', 'max:15', 'unique:contacts,cnic'],
				'gender' => ['required', 'in:male,female,other'],
			], [
				'cnic.required' => 'CNIC/NIC number is required.',
				'cnic.unique' => 'This CNIC/NIC is already registered in the system.',
				'gender.required' => 'Gender selection is required.',
				'gender.in' => 'Please select a valid gender option.',
			]);

			if ($validator->fails()) {
				return back()
					->withInput()
					->withErrors($validator)
					->with('error', 'Please fix the errors below.');
			}

			DB::transaction(function () use ($validatedData, &$contact, &$user) {
				// Step 1: Create Account record based on contact type
				$account = $this->createContactAccount($validatedData);

				// Step 2: Create Contact record with account_id
				$contactData = $validatedData;
				$contactData['account_id'] = $account->id;
				$contact = Contact::create($contactData);

				// Step 3: Update Account's model_id to reference the contact
				$account->update(['model_id' => $contact->id]);

				// Step 4: Use ContactService for additional setup (user creation, etc.)
				$contactService = app(\App\Services\ContactService::class);
				$contact = $contactService->enhanceContact($contact, $validatedData);

				// Check if user was created
				if ($contact->user_id) {
					$user = $contact->user;
				}
			});

			$this->logActivity('Contact created', $contact, [
				'action' => 'store',
				'contact_data' => $validatedData,
				'user_created' => $user ? true : false
			]);

			$message = 'Contact created successfully.';
			if ($user) {
				$message .= ' User account also created.';
			}
			if ($contact->type === 'shop_manager') {
				$message .= ' Shop information also created.';
			}

			return redirect()->route('contacts.index')->with('success', $message);
		} catch (\Illuminate\Validation\ValidationException $e) {
			return back()
				->withInput()
				->withErrors($e->errors())
				->with('error', 'Please fix the errors below.');
		} catch (\Throwable $e) {
			$this->logError('Contact creation', $e, [
				'action' => 'store',
				'contact_data' => $request->all()
			]);

			report($e);
			$errorMessage = config('app.debug') ? $e->getMessage() : 'Failed to create contact.';
			return back()
				->withInput()
				->withErrors(['error' => $errorMessage])
				->with('error', 'Failed to create contact. Please try again.');
		}
	}

	public function edit(Contact $contact): View
	{
        $roles = \Spatie\Permission\Models\Role::where('id', '>', 2)->pluck('name', 'id')->toArray();
        $shops = Account::where('model_type', 'shop')->where('is_active', true)->get();

		return view('contacts.edit', compact('contact', 'roles', 'shops'));
	}

	public function update(UpdateContactRequest $request, Contact $contact): RedirectResponse
	{
		try {
			// Block edit if linked with PR/PO/GatePass
			$linked = false;
			if (method_exists($contact, 'purchaseOrders') && $contact->purchaseOrders()->exists()) $linked = true;
			if (method_exists($contact, 'purchaseRequests') && $contact->purchaseRequests()->exists()) $linked = true;
			if (method_exists($contact, 'gatePasses') && $contact->gatePasses()->exists()) $linked = true;
			if ($linked) {
				throw new \Illuminate\Validation\ValidationException(validator([], []), redirect()->back()->withErrors(['error' => 'This Contact is linked with Purchase Requests/Orders or Gate Passes and cannot be edited. Use status toggle instead.'])->withInput());
			}
			$oldData = $contact->toArray();
			$userSynced = false;

			DB::transaction(function () use ($request, $contact, &$userSynced) {
				// Use ContactService to update contact with all related data
				$contactService = app(\App\Services\ContactService::class);
				$contact = $contactService->updateContact($contact, $request->validated());

				// Check if user was synced
				if ($contact->user_id && $contact->user && isset($request->validated()['is_active'])) {
					$contact->user->update(['is_active' => $request->validated()['is_active']]);
					$userSynced = true;
				}
			});

			$this->logActivity('Contact updated', $contact, [
				'action' => 'update',
				'old_data' => $oldData,
				'new_data' => $request->validated(),
				'user_synced' => $userSynced
			]);

			$message = 'Contact updated successfully.';
			if ($userSynced) {
				$message .= ' User status also synced.';
			}
			if ($contact->type === 'shop_manager') {
				$message .= ' Shop information also updated.';
			}

			return redirect()->route('contacts.index')->with('success', $message);
		} catch (\Throwable $e) {
			$this->logError('Contact update', $e, [
				'action' => 'update',
				'contact_id' => $contact->id,
				'contact_data' => $request->validated()
			]);

			report($e);
			return back()->withInput()->withErrors(['error' => 'Failed to update contact.']);
		}
	}

	public function destroy(Contact $contact): RedirectResponse
	{
		try {
			// Block delete if linked
			if ((method_exists($contact, 'purchaseOrders') && $contact->purchaseOrders()->exists())
				|| (method_exists($contact, 'purchaseRequests') && $contact->purchaseRequests()->exists())
				|| (method_exists($contact, 'gatePasses') && $contact->gatePasses()->exists())) {
				throw new \Illuminate\Validation\ValidationException(validator([], []), redirect()->back()->withErrors(['error' => 'This Contact is linked with Purchase Requests/Orders or Gate Passes and cannot be deleted. Use status toggle instead.']));
			}
			$contactData = $contact->toArray();
			DB::transaction(function () use ($contact) {
				$contact->delete();
			});

			$this->logActivity('Contact deleted', null, [
				'action' => 'destroy',
				'contact_id' => $contact->id,
				'contact_data' => $contactData
			]);

			return redirect()->route('contacts.index')->with('success', 'Contact deleted successfully.');
		} catch (\Throwable $e) {
			$this->logError('Contact deletion', $e, [
				'contact_id' => $contact->id,
				'action' => 'destroy'
			]);

			report($e);
			return back()->withErrors(['error' => 'Failed to delete contact.']);
		}
	}

	public function toggleStatus(Request $request, Contact $contact): RedirectResponse
	{
		try {
			$nextStatus = $contact->status === 'active' ? 'inactive' : 'active';
			DB::transaction(function () use ($contact, $nextStatus) {
				$contact->update(['status' => $nextStatus]);
				if ($contact->user_id && $contact->user) {
					$contact->user->update(['is_active' => $nextStatus === 'active']);
				}
			});
			return back()->with('success', 'Contact status updated to '.$nextStatus.'.');
		} catch (\Throwable $e) {
			report($e);
			return back()->withErrors(['error' => 'Failed to toggle contact status.']);
		}
	}

	public function search(Request $request)
	{
		$q = (string) $request->get('q', '');
		$page = (int) $request->get('page', 1);
		$limit = 10;

		$query = Contact::query()
			->when($q, function($query) use ($q) {
				$query->where(function($sub) use ($q) {
					$sub->where('name', 'like', "%{$q}%")
						->orWhere('phone', 'like', "%{$q}%")
						->orWhere('email', 'like', "%{$q}%");
				});
			})
			->where('is_active', 1)
			->orderBy('name');

		$total = $query->count();
		$contacts = $query->skip(($page - 1) * $limit)
			->take($limit)
			->get(['id', 'name', 'phone', 'email']);

		return response()->json([
			'results' => $contacts->map(function($contact) {
				return [
					'id' => $contact->id,
					'text' => $contact->name . ' (' . $contact->phone . ')'
				];
			}),
			'pagination' => [
				'more' => ($page * $limit) < $total
			]
		]);
	}

	public function checkUsername(Request $request): JsonResponse
	{
		$username = $request->input('username');

		if (empty($username)) {
			return response()->json([
				'available' => false,
				'message' => 'Username is required'
			]);
		}

		// Check if username exists in users table
		$userExists = \App\Models\User::where('username', $username)->exists();

		return response()->json([
			'available' => !$userExists,
			'message' => $userExists ? 'Username already taken' : 'Username is available'
		]);
	}

	/**
	 * Create Account record based on contact type and Chart of Accounts mapping
	 */
	private function createContactAccount(array $contactData): Account
	{
		// Map contact types to Chart of Account IDs
		$chartOfAccountMapping = [
			'customer' => 13,      // Customer Accounts (Code 1121)
			'supplier' => 21,      // Supplier Accounts (Code 2111)
			'employee' => 63,      // Employee Account (Code 2130)
			'shop_manager' => 63,  // Employee Account (Code 2130)
			'shop_employee' => 63, // Employee Account (Code 2130)
		];

		$contactType = $contactData['type'];
		$chartOfAccountId = $chartOfAccountMapping[$contactType] ?? null;

		if (!$chartOfAccountId) {
			throw new \InvalidArgumentException("Invalid contact type: {$contactType}");
		}

		// Verify Chart of Account exists
		$chartOfAccount = ChartOfAccount::find($chartOfAccountId);
		if (!$chartOfAccount) {
			throw new \Exception("Chart of Account not found for contact type: {$contactType}");
		}

		// Create Account record
		$account = Account::create([
			'name' => $contactData['name'],
			'model_type' => 'contact',
			'model_id' => 0, // Temporary value, will be updated after contact creation
			'chart_of_account_id' => $chartOfAccountId,
			'code' => $this->generateAccountCode($chartOfAccount->code, $contactData['name']),
			'description' => "Account for {$contactType}: {$contactData['name']}",
			'balance' => 0.00,
			'is_active' => $contactData['is_active'] ?? true,
		]);

		return $account;
	}

	/**
	 * Generate unique account code based on chart of account and contact name
	 */
	private function generateAccountCode(string $chartCode, string $contactName): string
	{
		// Create a base code using chart code + sanitized contact name
		$sanitizedName = preg_replace('/[^A-Za-z0-9]/', '', $contactName);
		$baseCode = $chartCode . '-' . strtoupper(substr($sanitizedName, 0, 6));

		// Ensure uniqueness by appending a number if needed
		$counter = 1;
		$finalCode = $baseCode;

		while (Account::where('code', $finalCode)->exists()) {
			$finalCode = $baseCode . '-' . str_pad($counter, 3, '0', STR_PAD_LEFT);
			$counter++;
		}

		return $finalCode;
	}
}
