<?php

namespace App\Http\Controllers;

use App\Models\OrganizationCompany;
use App\Models\OrganizationSetting;
use App\Support\BrandingManager;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Storage;

class ProfileCompanySettingsController extends Controller
{
    public function update(Request $request, BrandingManager $brandingManager): RedirectResponse
    {
        $validated = $request->validate([
            'group_companies_enabled' => ['nullable', 'boolean'],
            'companies' => ['nullable', 'array'],
            'companies.*.id' => ['nullable', 'integer', 'exists:organization_companies,id'],
            'companies.*.name' => ['nullable', 'string', 'max:255'],
            'companies.*.requisites' => ['nullable', 'string'],
            'companies.*.address' => ['nullable', 'string'],
            'companies.*.phones' => ['nullable', 'string'],
            'companies.*.parent_id' => ['nullable', 'integer', 'exists:organization_companies,id'],
            'companies.*.parent_index' => ['nullable', 'integer', 'min:0'],
            'companies.*.remove_logo' => ['nullable', 'boolean'],
            'companies.*.delete' => ['nullable', 'boolean'],
            'companies.*.logo' => ['nullable', 'image', 'max:10240'],
        ]);

        $setting = OrganizationSetting::current();
        $setting->group_companies_enabled = $request->boolean('group_companies_enabled');
        $setting->save();

        $existing = OrganizationCompany::query()
            ->orderBy('id')
            ->get()
            ->keyBy('id');

        $rows = is_array($validated['companies'] ?? null) ? $validated['companies'] : [];
        $activeCount = collect($rows)->filter(function ($row): bool {
            if (! is_array($row)) {
                return false;
            }

            $name = trim((string) ($row['name'] ?? ''));
            $isDelete = (bool) ($row['delete'] ?? false);

            return $name !== '' && ! $isDelete;
        })->count();

        if ($setting->group_companies_enabled && $activeCount > 30) {
            return Redirect::back()
                ->withErrors(['companies' => __('You can add up to 30 companies.')])
                ->withInput();
        }

        $order = 1;
        $indexToId = [];
        $deferredParents = [];

        foreach ($rows as $index => $row) {
            $id = (int) ($row['id'] ?? 0);
            $name = trim((string) ($row['name'] ?? ''));
            $isDelete = (bool) ($row['delete'] ?? false);
            $parentId = (int) ($row['parent_id'] ?? 0);
            $parentIndex = isset($row['parent_index']) && $row['parent_index'] !== ''
                ? (int) $row['parent_index']
                : null;

            if ($id > 0 && ! $existing->has($id)) {
                continue;
            }

            /** @var OrganizationCompany|null $company */
            $company = $id > 0 ? $existing->get($id) : null;

            if ($isDelete || $name === '') {
                if ($company) {
                    $this->deleteLogo($company);
                    $company->delete();
                }
                continue;
            }

            if (! $company) {
                $company = new OrganizationCompany();
            }

            $company->fill([
                'name' => $name,
                'requisites' => $this->nullableText($row['requisites'] ?? null),
                'address' => $this->nullableText($row['address'] ?? null),
                'phones' => $this->normalizePhones($row['phones'] ?? null),
                'sort_order' => $order++,
            ]);

            $resolvedParentId = null;
            if ($parentId > 0 && $parentId !== $id) {
                $resolvedParentId = $parentId;
            } elseif ($parentIndex !== null && $parentIndex !== $index && array_key_exists($parentIndex, $indexToId)) {
                $resolvedParentId = $indexToId[$parentIndex];
            }
            $company->parent_id = $resolvedParentId;

            if ((bool) ($row['remove_logo'] ?? false) && $company->logo_path) {
                Storage::disk('public')->delete((string) $company->logo_path);
                $company->logo_path = null;
            }

            $logo = $request->file("companies.$index.logo");
            if ($logo) {
                $newPath = $logo->store('organization-logos', 'public');
                if ($company->logo_path && $company->logo_path !== $newPath) {
                    Storage::disk('public')->delete((string) $company->logo_path);
                }
                $company->logo_path = $newPath;
            }

            $company->save();
            $indexToId[$index] = $company->id;

            if ($resolvedParentId === null && $parentIndex !== null && $parentIndex !== $index) {
                $deferredParents[] = [$company->id, $parentIndex];
            }
        }

        if ($deferredParents !== []) {
            foreach ($deferredParents as [$companyId, $parentIndex]) {
                if (! array_key_exists($parentIndex, $indexToId)) {
                    continue;
                }

                $target = $existing->get($companyId) ?? OrganizationCompany::query()->find($companyId);
                if (! $target) {
                    continue;
                }

                $target->parent_id = $indexToId[$parentIndex];
                $target->save();
            }
        }

        $brandingManager->flush();

        return Redirect::route('profile.edit', ['section' => 'company'])
            ->with('status', 'company-settings-updated');
    }

    private function normalizePhones(mixed $value): array
    {
        if (! is_string($value)) {
            return [];
        }

        $rows = preg_split('/\r\n|\r|\n/', $value) ?: [];

        return array_values(array_filter(
            array_map(static fn ($item) => trim((string) $item), $rows),
            static fn (string $item) => $item !== ''
        ));
    }

    private function nullableText(mixed $value): ?string
    {
        if (! is_string($value)) {
            return null;
        }

        $trimmed = trim($value);

        return $trimmed === '' ? null : $trimmed;
    }

    private function deleteLogo(OrganizationCompany $company): void
    {
        if ($company->logo_path) {
            Storage::disk('public')->delete((string) $company->logo_path);
        }
    }
}
