<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Models\User;
use App\Services\ActivityLogService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class DepartmentController extends Controller
{
    public function __construct(protected ActivityLogService $activityLogService) {}

    public function index(): JsonResponse
    {
        try {
            $departments = Department::with(['manager', 'children', 'members'])->orderBy('sort_order')->get();
            $departmentIds = $departments->pluck('id');

            $tree = $departments
                ->filter(fn ($department) => $department->parent_id === null || ! $departmentIds->contains($department->parent_id))
                ->values()
                ->map(fn ($d) => $this->formatNode($d, $departments));

            return response()->json([
                'success' => true,
                'data' => $tree,
                'flat' => $departments->values()->map(fn ($d) => [
                    'id' => $d->id,
                    'name' => $d->name,
                    'type' => $d->type ?? 'department',
                    'parent_id' => $d->parent_id,
                    'parent_name' => $departments->firstWhere('id', $d->parent_id)?->name,
                    'children_count' => $departments->where('parent_id', $d->id)->count(),
                ]),
                'message' => 'ساختار سازمانی',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در دریافت ساختار سازمانی',
            ], 500);
        }
    }

    private function formatNode($dept, $all): array
    {
        $children = $all->where('parent_id', $dept->id)->values();

        return [
            'id' => $dept->id,
            'name' => $dept->name,
            'description' => $dept->description,
            'type' => $dept->type ?? 'department',
            'parent_id' => $dept->parent_id,
            'manager' => $dept->manager ? ['id' => $dept->manager->id, 'name' => $dept->manager->name] : null,
            'manager_id' => $dept->manager_id,
            'manager_changed_at' => $dept->manager_changed_at,
            'is_active' => $dept->is_active,
            'sort_order' => $dept->sort_order,
            'users_count' => $dept->members()->count() ?: $dept->users()->count(),
            'children' => $children->map(fn ($c) => $this->formatNode($c, $all)),
        ];
    }

    public function store(Request $request): JsonResponse
    {
        try {
            $request->validate([
                'name' => 'required|string|max:255',
                'description' => 'nullable|string',
                'type' => 'nullable|string|in:organization,department,unit,team',
                'parent_id' => 'nullable|exists:departments,id',
                'manager_id' => 'nullable|exists:users,id',
                'is_active' => 'nullable|boolean',
                'sort_order' => 'nullable|integer',
            ]);

            $data = $request->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
            $data['type'] = $data['type'] ?? 'department';
            $data['is_active'] = $data['is_active'] ?? true;
            if (! empty($data['manager_id'])) {
                $data['manager_changed_at'] = now();
            }
            $dept = Department::create($data);

            $this->activityLogService->log(
                $request->user()?->id,
                'create_department',
                "بخش {$dept->name} ایجاد شد",
                'department',
                $dept->id,
                null,
                null,
                ['new' => $dept->only(['name', 'type', 'parent_id', 'manager_id', 'is_active'])]
            );

            return response()->json([
                'success' => true,
                'data' => $dept->load('manager'),
                'message' => 'دپارتمان با موفقیت ایجاد شد',
            ], 201);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در ایجاد دپارتمان',
            ], 500);
        }
    }

    public function show(Department $department): JsonResponse
    {
        try {
            $department->load(['manager', 'parent', 'children']);

            return response()->json([
                'success' => true,
                'data' => $department,
                'message' => 'اطلاعات دپارتمان',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در دریافت اطلاعات دپارتمان',
            ], 500);
        }
    }

    public function update(Request $request, Department $department): JsonResponse
    {
        try {
            $request->validate([
                'name' => 'sometimes|required|string|max:255',
                'description' => 'nullable|string',
                'type' => 'nullable|string|in:organization,department,unit,team',
                'parent_id' => 'nullable|exists:departments,id',
                'manager_id' => 'nullable|exists:users,id',
                'is_active' => 'nullable|boolean',
                'sort_order' => 'nullable|integer',
            ]);

            $old = $department->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
            $payload = $request->only(['name', 'description', 'type', 'parent_id', 'manager_id', 'is_active', 'sort_order']);
            if (array_key_exists('manager_id', $payload) && (int) $payload['manager_id'] !== (int) $department->manager_id) {
                $payload['manager_changed_at'] = now();
            }
            $department->update($payload);

            $changed = collect($payload)
                ->except('manager_changed_at')
                ->filter(fn ($value, $key) => array_key_exists($key, $old) && $old[$key] != $department->{$key})
                ->map(fn ($value, $key) => ['old' => $old[$key], 'new' => $department->{$key}])
                ->all();

            if (! empty($changed)) {
                $this->activityLogService->log(
                    $request->user()?->id,
                    array_key_exists('manager_id', $changed) ? 'change_department_manager' : 'update_department',
                    array_key_exists('manager_id', $changed)
                        ? "مدیر بخش {$department->name} تغییر کرد"
                        : "بخش {$department->name} ویرایش شد",
                    'department',
                    $department->id,
                    null,
                    null,
                    ['changes' => $changed]
                );
            }

            return response()->json([
                'success' => true,
                'data' => $department->fresh()->load('manager'),
                'message' => 'دپارتمان به‌روزرسانی شد',
            ]);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در به‌روزرسانی دپارتمان',
            ], 500);
        }
    }

    public function destroy(Request $request, Department $department): JsonResponse
    {
        try {
            if ($department->children()->exists()) {
                return response()->json([
                    'success' => false,
                    'message' => 'این دپارتمان دارای زیرمجموعه است. ابتدا زیرمجموعه‌ها را حذف کنید.',
                ], 400);
            }
            if ($department->members()->exists() || $department->users()->exists()) {
                return response()->json([
                    'success' => false,
                    'message' => 'این بخش عضو دارد. ابتدا اعضا را منتقل کنید یا بخش را غیرفعال کنید.',
                ], 400);
            }

            $departmentName = $department->name;
            $departmentId = $department->id;
            $department->delete();

            $this->activityLogService->log(
                $request->user()?->id,
                'delete_department',
                "بخش {$departmentName} حذف شد",
                'department',
                $departmentId
            );

            return response()->json([
                'success' => true,
                'message' => 'دپارتمان حذف شد',
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'خطا در حذف دپارتمان',
            ], 500);
        }
    }

    public function addMember(Request $request, Department $department): JsonResponse
    {
        try {
            $request->validate([
                'user_id' => 'required|exists:users,id',
                'role_in_team' => 'nullable|string|max:255',
                'is_primary' => 'nullable|boolean',
            ]);

            $user = User::findOrFail($request->user_id);
            $isPrimary = $request->boolean('is_primary');
            $this->syncMember($department, $user, $request->role_in_team, $isPrimary);

            $this->activityLogService->log(
                $request->user()?->id,
                'add_department_member',
                "{$user->name} به {$department->name} اضافه شد",
                'department',
                $department->id,
                null,
                null,
                ['user_id' => $user->id, 'role_in_team' => $request->role_in_team, 'is_primary' => $isPrimary]
            );

            return response()->json(['success' => true, 'message' => 'عضو اضافه شد']);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'خطا در افزودن عضو'], 500);
        }
    }

    public function updateMember(Request $request, Department $department, User $user): JsonResponse
    {
        try {
            $request->validate([
                'role_in_team' => 'nullable|string|max:255',
                'is_primary' => 'nullable|boolean',
            ]);

            $isPrimary = $request->boolean('is_primary');
            $this->syncMember($department, $user, $request->role_in_team, $isPrimary);

            $this->activityLogService->log(
                $request->user()?->id,
                'update_department_member',
                "عضویت {$user->name} در {$department->name} ویرایش شد",
                'department',
                $department->id,
                null,
                null,
                ['user_id' => $user->id, 'role_in_team' => $request->role_in_team, 'is_primary' => $isPrimary]
            );

            return response()->json(['success' => true, 'message' => 'عضویت به‌روزرسانی شد']);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'خطا در به‌روزرسانی عضویت'], 500);
        }
    }

    public function removeMember(Request $request, Department $department, User $user): JsonResponse
    {
        try {
            $department->members()->detach($user->id);
            if ((int) $user->department_id === (int) $department->id) {
                $primary = $user->departments()->wherePivot('is_primary', true)->first();
                $user->update([
                    'department_id' => $primary?->id,
                    'department' => $primary?->name,
                ]);
            }

            $this->activityLogService->log(
                $request->user()?->id,
                'remove_department_member',
                "{$user->name} از {$department->name} حذف شد",
                'department',
                $department->id,
                null,
                null,
                ['user_id' => $user->id]
            );

            return response()->json(['success' => true, 'message' => 'عضو حذف شد']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'خطا در حذف عضو'], 500);
        }
    }

    public function transferMember(Request $request, Department $department, User $user): JsonResponse
    {
        try {
            $request->validate([
                'target_department_id' => 'required|exists:departments,id',
                'role_in_team' => 'nullable|string|max:255',
                'is_primary' => 'nullable|boolean',
            ]);

            $target = Department::findOrFail($request->target_department_id);
            $department->members()->detach($user->id);
            $this->syncMember($target, $user, $request->role_in_team, $request->boolean('is_primary', true));

            $this->activityLogService->log(
                $request->user()?->id,
                'transfer_department_member',
                "{$user->name} از {$department->name} به {$target->name} منتقل شد",
                'department',
                $department->id,
                null,
                null,
                ['user_id' => $user->id, 'from' => $department->id, 'to' => $target->id]
            );

            return response()->json(['success' => true, 'message' => 'عضو منتقل شد']);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'خطا در انتقال عضو'], 500);
        }
    }

    private function syncMember(Department $department, User $user, ?string $roleInTeam, bool $isPrimary): void
    {
        if ($isPrimary) {
            DB::table('department_user')->where('user_id', $user->id)->update(['is_primary' => false]);
            $user->update([
                'department_id' => $department->id,
                'department' => $department->name,
            ]);
        }

        $department->members()->syncWithoutDetaching([
            $user->id => [
                'role_in_team' => $roleInTeam,
                'is_primary' => $isPrimary,
                'joined_at' => now(),
            ],
        ]);
    }
}
