<?php

namespace App\Http\Controllers;

use App\Models\Account;
use App\Models\Activity;
use App\Models\Company;
use App\Models\Contact;
use App\Models\ContactEmail;
use App\Models\ContactLanguage;
use App\Models\ContactPhoneNum;
use App\Models\ContactSocialMedia;
use App\Models\Country;
use App\Models\Language;
use App\Models\Lead;
use App\Models\Deal;
use App\Models\DealStage;
use App\Models\Project;
use App\Models\CrmCase;
use App\Models\Survey;
use App\Models\CampaignTarget;
use App\Models\TradeDocument;
use App\Models\MeetingThirdPartyIntegration;
use App\Models\Priority;
use App\Models\Repeat;
use App\Models\Status;
use App\Models\User;
use App\Models\UserAccess;
use App\Models\AccessType;
use App\Support\CrmAccess;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

class AccountController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('permission:list_accounts')->only(['index']);
        $this->middleware('permission:list_accounts')->only(['show']);
        $this->middleware('permission:create_accounts')->only(['create', 'store']);
        $this->middleware('permission:update_accounts')->only(['edit', 'update']);
        $this->middleware('permission:delete_accounts')->only(['destroy']);
    }
    
    public function index(Request $request)
    {

        $user = auth()->user();
        $businessId = $user->business_id;
        $this->useDefaultDateRange($request);

        $request->validate([
            'q'=>['nullable','string','max:100'],'status'=>['nullable',Rule::in(['active','inactive','archived'])],
            'account_type'=>['nullable','string','max:100'],'date_from'=>['nullable','date'],
            'date_to'=>['nullable','date','after_or_equal:date_from'],
        ]);
        $search = trim((string) $request->input('q'));
        $accountPaginator = $this->getAccessibleAccounts($user->id)
            ->when($request->filled('status'),fn($q)=>$q->where('status',$request->status))
            ->when($request->filled('account_type'),fn($q)=>$q->where('account_type',$request->account_type))
            ->when($request->filled('date_from'),fn($q)=>$q->whereDate('created_at','>=',$request->date_from))
            ->when($request->filled('date_to'),fn($q)=>$q->whereDate('created_at','<=',$request->date_to))
            ->when($search !== '', fn ($query) => $query->where(fn ($filter) => $filter
                ->where('account_name', 'like', "%{$search}%")
                ->orWhere('account_number', 'like', "%{$search}%")
                ->orWhere('website', 'like', "%{$search}%")
                ->orWhere('account_type', 'like', "%{$search}%")))
            ->orderBy('account_name')->paginate(25)->withQueryString();
        $accounts = collect($accountPaginator->items());

        $activities = collect();
        $priorities = Priority::all();
        $countries = Country::all();
        $meetings = MeetingThirdPartyIntegration::all();
        $eventStatuses = Status::all();
        $companies = Company::all();
        $repeats = Repeat::all();
        $users = $this->getAccessibleUsers();
        $contacts = Contact::where('business_id', $businessId)->orderBy('first_name')
            ->limit(250)->get(['id','first_name','last_name']);



        $activityTypes = [
            1 => 'Call',
            2 => 'Appointment',
            3 => 'Task',
            4 => 'Event',
            5 => 'Deadline',
            6 => 'Other Activity',
            7 => 'Letter',
            8 => 'Fax',
            9 => 'Email',
            10 => 'Campaign',
        ];

        // dd($contacts);
        return view('account.account', compact('accounts', 'accountPaginator', 'activities', 'activityTypes', 'priorities', 'countries', 'meetings', 'eventStatuses', 'companies', 'repeats', 'contacts', 'users'));
    }

    private function getAccessibleAccounts($userId)
    {
        $accessibleUserIds = $this->getAccessibleUserIds($userId);
        
        return Account::with([
            'contactPhones',
            'contactEmails',
            'contactSocialMedia',
            'contactLanguages'
        ])
            ->whereIn('contact_owner_id', $accessibleUserIds)
            ->where('business_id', auth()->user()->business_id)
            ;
            
    }

    private function getAccessibleUserIds($currentUserId)
    {
        return CrmAccess::accessibleUserIds(User::findOrFail($currentUserId));
    }

    private function getAccessibleUsers()
    {
        $accessibleUserIds = $this->getAccessibleUserIds(auth()->id());
        return User::whereIn('id', $accessibleUserIds)->get();
    }

    public function create()
    {
        $languages = Language::all();
        $contacts = Contact::where('business_id', auth()->user()->business_id)->get();
        $accounts = Account::where('business_id', auth()->user()->business_id)->get();
        $leads = Lead::all();
        $users = User::all();

        return view('account.account-create', compact('languages', 'contacts', 'accounts', 'leads', 'users'));
    }

    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'contact_methods' => 'required|array',  // Ensure it's an array
            'account_name' => 'required|string|max:255',
            'account_type' => 'required|string|max:100',
            'primary_contact' => ['required', Rule::exists('contacts', 'id')->where('business_id', auth()->user()->business_id)],
            'contact_ids' => 'nullable|array',
            'contact_ids.*' => ['integer', Rule::exists('contacts', 'id')->where('business_id', auth()->user()->business_id)],
            'contact_owner' => ['required', Rule::exists('users', 'id')->where('business_id', auth()->user()->business_id)],
            'parent_account_id' => ['nullable', 'integer', Rule::exists('accounts', 'id')->where('business_id', auth()->user()->business_id)],
        ]);
        // dd($request);

        $account = Account::create([
            'business_id' => auth()->user()->business_id,
            'primary_contact_id' => $request->primary_contact,
            'contact_owner_id' => $request->contact_owner,
            'parent_account_id' => $request->parent_account_id,
            'account_type' => $request->account_type,
            'account_name' => $validatedData['account_name'],
            'account_number' => $request->account_number,
            'billing_address_1' => $request->address1,
            'billing_address_2' => $request->address2,
            'billing_city' => $request->city,
            'billing_province' => $request->province,
            'billing_zip_code' => $request->zipcode,
            'billing_country_id' => $request->country_id,
            'website' => $request->website,
            'fax' => $request->fax,
            'industry_id' => $request->industry_id,
            'sic_code' => $request->sic_code,
            'contact_method' =>  json_encode($request->contact_methods),
            'total_revenue' => $request->total_revenue,
            'account_type' => $validatedData['account_type'],
            'ownership' => $request->ownership,
            'originating_lead_id' => $request->originating_lead_id,
            'credit_limit' => $request->credit_limit,
            'payment_terms' => $request->payment_terms,
            'rating' => $request->rating,
            'status' => $request->status,

        ]);

        $this->syncContacts($account, $request->input('contact_ids', []));


        foreach ($request->input('phones', []) as $index => $phone) {
            ContactPhoneNum::create([
                'account_id' => $account->id,
                'phone_type_id' => $request->input('phone_types')[$index],
                'phone' => $phone,
            ]);
        }

        // Store emails
        foreach ($request->input('emails', []) as $index => $email) {
            ContactEmail::create([
                'account_id' => $account->id,
                'email_type_id' => $request->input('email_types')[$index],
                'email' => $email,
            ]);
        }

        $socialMediaTypeMap = [
            'facebook' => 1,
            'linkedin' => 2,
        ];

        foreach ($request->input('social_media_values', []) as $index => $social_media_value) {
            $socialMediaType = $request->input('social_media_types')[$index];

            $socialMediaTypeId = $socialMediaTypeMap[$socialMediaType] ?? null;

            if ($socialMediaTypeId) {
                ContactSocialMedia::create([
                    'account_id' => $account->id,
                    'social_media_type_id' => $socialMediaTypeId,
                    'value' => $social_media_value,
                ]);
            }
        }

        foreach ($request->languages as $languageId) {
            ContactLanguage::create([
                'account_id' => $account->id,
                'language_id' => $languageId,
            ]);
        }



        return redirect()->route('account')->with('success', 'Account created successfully!');
    }

    public function show(Request $request)
    {

        $accountId = $request->query('id');
        $account = Account::with([
            'contactPhones',
            'contactEmails',
            'contactSocialMedia',
            'contactLanguages.language',
            'assignedUser', 'billingCountry',
            'primaryContact',
            'contacts.contactPhones',
            'contacts.contactEmails',
            'parentAccount.parentAccount',
            'childAccounts',
        ])->where('business_id', auth()->user()->business_id)->findOrFail($accountId);

        $leads = Lead::where('business_id', auth()->user()->business_id)
            ->where(function ($query) use ($account) {
                $query->where('id', $account->originating_lead_id);
                if ($account->primary_contact_id) {
                    $query->orWhere('primary_contact_id', $account->primary_contact_id);
                }
            })
            ->get();

        $deals = Deal::with(['dealProductLine.product'])
            ->where('business_id', auth()->user()->business_id)
            ->where(function ($query) use ($account) {
                $query->where('account_id', $account->id)
                    ->orWhereHas('accounts', fn ($accounts) => $accounts->where('accounts.id', $account->id));
            })
            ->get();

        $dealIds = $deals->pluck('id');
        $wonStageIds = DealStage::where('name', 'Closed Won')->pluck('id');
        $closedDealValue = $deals->whereIn('stage_id', $wonStageIds)
            ->sum(fn ($deal) => (float) ($deal->grand_total ?: $deal->estimate_amount));
        $activities = Activity::with(['attendees'])->where('business_id', auth()->user()->business_id)
            ->where('account_id', $account->id)->latest('start_date')->latest('start_time')->get();
        $invitedMeetings = $activities->where('activity_type_id', 2);
        $projects = Project::where('business_id', $account->business_id)
            ->where(fn ($query) => $query->where('account_id', $account->id)->orWhereIn('deal_id', $dealIds))
            ->latest()->get();
        $products = $deals->flatMap->dealProductLine->unique('product_id')->values();
        $tradeDocuments = TradeDocument::where('business_id', $account->business_id)
            ->whereIn('deal_id', $dealIds)->latest()->get();
        $campaigns = CampaignTarget::with('campaign')->where('target_type', Account::class)
            ->where('target_id', $account->id)->latest()->get();
        $cases = CrmCase::where('business_id', $account->business_id)
            ->where('account_id', $account->id)->latest()->get();
        $surveys = $account->surveys()->latest('surveys.created_at')->get();

        return view('account.account-view', compact(
            'account', 'leads', 'deals', 'closedDealValue', 'activities', 'invitedMeetings',
            'projects', 'products', 'tradeDocuments', 'campaigns', 'cases', 'surveys'
        ));
    }

    public function edit(Request $request)
    {
        $accountId = $request->query('id');

        $account = Account::with(['contactPhones', 'contactEmails', 'contactSocialMedia', 'contactLanguages', 'contacts'])->findOrFail($accountId);
        $languages = Language::all();
        $contacts = Contact::where('business_id', auth()->user()->business_id)->get();
        $accounts = Account::where('business_id', auth()->user()->business_id)->get();
        $leads = Lead::all();
        $users = User::all();

        $account->contact_method = json_decode($account->contact_method, true);


        return view('account.account-edit', compact('account', 'languages', 'contacts', 'accounts', 'leads', 'users'));
    }


    public function update(Request $request, $id)
    {
        $account = Account::where('business_id', auth()->user()->business_id)->findOrFail($id);
        $request->validate([
            'contact_ids' => 'nullable|array',
            'contact_ids.*' => ['integer', Rule::exists('contacts', 'id')->where('business_id', auth()->user()->business_id)],
            'contact_owner' => ['required', Rule::exists('users', 'id')->where('business_id', auth()->user()->business_id)],
            'parent_account_id' => ['nullable', 'integer', 'not_in:'.$account->id, Rule::exists('accounts', 'id')->where('business_id', auth()->user()->business_id)],
        ]);

        $parentId = $request->integer('parent_account_id') ?: null;
        while ($parentId) {
            abort_if($parentId === (int) $account->id, 422, 'Account hierarchy cannot contain a cycle.');
            $parentId = Account::where('business_id', auth()->user()->business_id)->find($parentId)?->parent_account_id;
        }

        // Update account details
        $account->update([
            'business_id' => auth()->user()->business_id,
            'primary_contact_id' => $request->primary_contact,
            'contact_owner_id' => $request->contact_owner,
            'parent_account_id' => $request->parent_account_id,
            'account_type' => $request->account_type,
            'account_name' => $request->account_name,
            'account_number' => $request->account_number,
            'billing_address_1' => $request->address1,
            'billing_address_2' => $request->address2,
            'billing_city' => $request->city,
            'billing_province' => $request->province,
            'billing_zip_code' => $request->zipcode,
            'billing_country_id' => $request->country_id,
            'website' => $request->website,
            'fax' => $request->fax,
            'industry_id' => $request->industry_id,
            'sic_code' => $request->sic_code,
            'contact_method' => json_encode($request->contact_methods),
            'total_revenue' => $request->total_revenue,
            'ownership' => $request->ownership,
            'originating_lead_id' => $request->originating_lead_id,
            'credit_limit' => $request->credit_limit,
            'payment_terms' => $request->payment_terms,
            'rating' => $request->rating,
            'status' => $request->status,
        ]);
        $this->syncContacts($account, $request->input('contact_ids', []));

        $account->contactPhones()->delete();
        foreach ($request->input('phones', []) as $index => $phone) {
            ContactPhoneNum::create([
                'account_id' => $account->id,
                'phone_type_id' => $request->input('phone_types')[$index],
                'phone' => $phone,
            ]);
        }

        $account->contactEmails()->delete();
        foreach ($request->input('emails', []) as $index => $email) {
            ContactEmail::create([
                'account_id' => $account->id,
                'email_type_id' => $request->input('email_types')[$index],
                'email' => $email,
            ]);
        }

        $account->contactSocialMedia()->delete();
        $socialMediaTypeMap = [
            'facebook' => 1,
            'linkedin' => 2,
        ];

        foreach ($request->input('social_media_values', []) as $index => $social_media_value) {
            $socialMediaType = $request->input('social_media_types')[$index];
            $socialMediaTypeId = $socialMediaTypeMap[$socialMediaType] ?? null;

            if ($socialMediaTypeId) {
                ContactSocialMedia::create([
                    'account_id' => $account->id,
                    'social_media_type_id' => $socialMediaTypeId,
                    'value' => $social_media_value,
                ]);
            }
        }

        $account->contactLanguages()->delete();
        foreach ($request->languages as $languageId) {
            ContactLanguage::create([
                'account_id' => $account->id,
                'language_id' => $languageId,
            ]);
        }

        return redirect()->route('account')->with('success', 'Account updated successfully!');
    }

    private function syncContacts(Account $account, array $contactIds): void
    {
        $ids = collect($contactIds)->map(fn ($id) => (int) $id)->filter();
        if ($account->primary_contact_id) $ids->push((int) $account->primary_contact_id);
        $sync = $ids->unique()->mapWithKeys(fn ($id) => [$id => [
            'is_primary' => $id === (int) $account->primary_contact_id,
        ]])->all();
        $account->contacts()->sync($sync);
    }


    public function destroy($id)
    {
        // Find the lead by ID
        $account = Account::findOrFail($id);



        $account->contactPhones()->delete();
        $account->contactEmails()->delete();
        $account->contactSocialMedia()->delete();
        $account->contactLanguages()->delete();


        $account->delete();

        return redirect()->route('account')->with('success', 'Account deleted successfully!');
    }
}
