<?php

namespace App\Http\Controllers;

use App\Models\Empresa;
use Illuminate\Database\QueryException;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Throwable;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class EmpresaController extends Controller
{
    public function index(Request $request): View
    {
        $this->ensureSuperadminAccess();

        $user = auth_user();
        $empresaIds = $user ? $user->accessibleEmpresaIds() : [];

        $empresas = Empresa::query()
            ->whereIn('id', $empresaIds)
            ->orderBy('nombre')
            ->paginate(15);

        return view('modules.empresas.index', [
            'empresas' => $empresas,
        ]);
    }

    public function store(Request $request): RedirectResponse
    {
        $this->ensureSuperadminAccess();

        $validated = $request->validate([
            'nombre' => ['required', 'string', 'max:150'],
            'slug' => ['nullable', 'string', 'max:120', Rule::unique('empresas', 'slug')],
            'nit' => ['nullable', 'string', 'max:40'],
            'email' => ['nullable', 'email', 'max:150'],
            'telefono' => ['nullable', 'string', 'max:40'],
            'direccion' => ['nullable', 'string', 'max:255'],
        ]);

        $validated['slug'] = $validated['slug'] ?? Str::slug($validated['nombre']);
        if ($validated['slug'] === '') {
            $validated['slug'] = 'empresa-'.Str::lower(Str::random(8));
        }

        $empresa = Empresa::create($validated);

        $user = auth_user();
        if ($user) {
            $user->empresas()->syncWithoutDetaching([
                $empresa->id => [
                    'es_principal' => 0,
                    'created_at' => now(),
                ],
            ]);
        }

        return $this->redirectAfterMutation('status', 'Empresa creada correctamente.');
    }

    public function edit(Empresa $empresa): View
    {
        $this->ensureSuperadminAccess();
        $this->ensureEmpresaAccess($empresa);

        return view('modules.empresas.edit', [
            'empresa' => $empresa,
        ]);
    }

    public function update(Request $request, Empresa $empresa): RedirectResponse
    {
        $this->ensureSuperadminAccess();
        $this->ensureEmpresaAccess($empresa);

        $validated = $request->validate([
            'nombre' => ['required', 'string', 'max:150'],
            'slug' => ['required', 'string', 'max:120', Rule::unique('empresas', 'slug')->ignore($empresa->id)],
            'nit' => ['nullable', 'string', 'max:40'],
            'email' => ['nullable', 'email', 'max:150'],
            'telefono' => ['nullable', 'string', 'max:40'],
            'direccion' => ['nullable', 'string', 'max:255'],
            'estado' => ['required', Rule::in(['activa', 'suspendida', 'bloqueada'])],
        ]);

        $empresa->update($validated);

        return $this->redirectAfterMutation('status', 'Empresa actualizada correctamente.');
    }

    public function deactivate(Empresa $empresa): RedirectResponse
    {
        $this->ensureSuperadminAccess();
        $this->ensureEmpresaAccess($empresa);

        if ($empresa->estado !== 'suspendida') {
            $empresa->update(['estado' => 'suspendida']);

            return $this->redirectAfterMutation('status', 'Empresa desactivada correctamente.');
        }

        return $this->redirectAfterMutation('status', 'La empresa ya estaba desactivada.');
    }

    public function reactivate(Empresa $empresa): RedirectResponse
    {
        $this->ensureSuperadminAccess();
        $this->ensureEmpresaAccess($empresa);

        if ($empresa->estado === 'activa') {
            return $this->redirectAfterMutation('status', 'La empresa ya estaba activa.');
        }

        $empresa->update(['estado' => 'activa']);

        return $this->redirectAfterMutation('status', 'Empresa reactivada correctamente.');
    }

    public function destroy(Empresa $empresa): RedirectResponse
    {
        $this->ensureSuperadminAccess();
        $this->ensureEmpresaAccess($empresa);

        if ((int) tenant_empresa_id() === (int) $empresa->id) {
            return $this->redirectAfterMutation('error', 'No puedes eliminar la empresa activa del contexto actual.');
        }

        if (has_permission('superadmin.acceso')) {
            try {
                DB::transaction(function () use ($empresa): void {
                    $this->purgeCompanyData($empresa);
                    $empresa->delete();
                });

                return $this->redirectAfterMutation('status', 'Empresa eliminada correctamente junto con su informacion relacionada.');
            } catch (Throwable) {
                return $this->redirectAfterMutation('error', $this->buildDeletionBlockedMessage($empresa));
            }
        }

        try {
            $empresa->delete();

            return $this->redirectAfterMutation('status', 'Empresa eliminada correctamente.');
        } catch (QueryException) {
            return $this->redirectAfterMutation('error', $this->buildDeletionBlockedMessage($empresa));
        }
    }

    private function redirectAfterMutation(string $flashKey, string $message): RedirectResponse
    {
        if (has_permission('superadmin.acceso')) {
            return redirect()
                ->route('superadmin.index', ['seccion' => 'empresas'])
                ->with($flashKey, $message);
        }

        return redirect()
            ->route('empresas.index')
            ->with($flashKey, $message);
    }

    private function ensureSuperadminAccess(): void
    {
        abort_unless(has_permission('superadmin.acceso'), 403, 'Solo superadmin puede administrar empresas.');
    }

    private function buildDeletionBlockedMessage(Empresa $empresa): string
    {
        $relations = [
            'suscripciones' => 'suscripciones',
            'sucursales' => 'sucursales',
            'usuarios' => 'usuarios',
            'usuario_empresa' => 'vinculos de usuarios',
            'clientes' => 'clientes',
            'productos' => 'productos',
            'ventas' => 'ventas',
            'configuracion_empresa' => 'configuraciones',
            'metodos_pago' => 'metodos de pago',
            'unidades_medida' => 'unidades de medida',
            'numeraciones_documentos' => 'numeraciones',
            'resoluciones_dian' => 'resoluciones DIAN',
            'impresoras' => 'impresoras',
            'categorias' => 'categorias',
            'marcas' => 'marcas',
            'proveedores' => 'proveedores',
            'compras' => 'compras',
            'ordenes_compra' => 'ordenes de compra',
            'recepciones_compra' => 'recepciones de compra',
            'pagos_suscripcion' => 'pagos de suscripcion',
            'aviso_cobros' => 'avisos de cobro',
            'saas_checkout_intents' => 'intentos de checkout',
            'ai_help_sessions' => 'sesiones de ayuda IA',
            'ai_help_messages' => 'mensajes de ayuda IA',
            'soporte_tickets' => 'tickets de soporte',
            'logs' => 'logs',
            'envios' => 'envios',
            'manychat_integraciones' => 'integraciones ManyChat',
            'manychat_pedidos' => 'pedidos ManyChat',
            'empresa_modulo_override' => 'overrides de modulos',
        ];

        $blockedBy = [];

        foreach ($relations as $table => $label) {
            if (! DB::getSchemaBuilder()->hasTable($table)) {
                continue;
            }

            $count = DB::table($table)
                ->where('empresa_id', $empresa->id)
                ->count();

            if ($count > 0) {
                $blockedBy[] = $label.' ('.$count.')';
            }
        }

        if ($blockedBy === []) {
            return 'No se pudo eliminar la empresa porque tiene informacion relacionada.';
        }

        return 'No se pudo eliminar la empresa porque tiene informacion relacionada en: '.implode(', ', array_slice($blockedBy, 0, 8)).'.';
    }

    private function purgeCompanyData(Empresa $empresa): void
    {
        $empresaId = (int) $empresa->id;
        $schema = DB::getSchemaBuilder();
        $now = now();

        $tableExists = static fn (string $table): bool => $schema->hasTable($table);
        $deleteWhereCompany = static function (string $table) use ($empresaId, $tableExists): void {
            if ($tableExists($table)) {
                DB::table($table)->where('empresa_id', $empresaId)->delete();
            }
        };

        $userIds = [];
        if ($tableExists('usuarios')) {
            $userIds = DB::table('usuarios')
                ->where('empresa_id', $empresaId)
                ->pluck('id')
                ->map(static fn ($id): int => (int) $id)
                ->all();

            DB::table('usuarios')
                ->where('empresa_id', $empresaId)
                ->update([
                    'sucursal_id' => null,
                    'updated_at' => $now,
                ]);
        }

        if ($tableExists('usuario_empresa')) {
            $linkedUserIds = DB::table('usuario_empresa')
                ->where('empresa_id', $empresaId)
                ->pluck('usuario_id')
                ->map(static fn ($id): int => (int) $id)
                ->all();

            $userIds = array_values(array_unique(array_merge($userIds, $linkedUserIds)));
        }

        if ($tableExists('soporte_tickets') && $tableExists('soporte_eventos')) {
            $ticketIds = DB::table('soporte_tickets')
                ->where('empresa_id', $empresaId)
                ->pluck('id')
                ->all();

            if ($ticketIds !== []) {
                DB::table('soporte_eventos')->whereIn('ticket_id', $ticketIds)->delete();
            }
        }

        $deleteWhereCompany('soporte_tickets');
        $deleteWhereCompany('ai_help_messages');
        $deleteWhereCompany('ai_help_sessions');
        $deleteWhereCompany('pagos_suscripcion');
        $deleteWhereCompany('aviso_cobros');
        $deleteWhereCompany('saas_checkout_intents');
        $deleteWhereCompany('manychat_pedidos');
        $deleteWhereCompany('manychat_integraciones');
        $deleteWhereCompany('envios');
        $deleteWhereCompany('logs');
        $deleteWhereCompany('notificacion_vistas');
        $deleteWhereCompany('empresa_modulo_override');

        $deleteWhereCompany('recepcion_compra_detalles');
        $deleteWhereCompany('recepciones_compra');
        $deleteWhereCompany('orden_compra_detalles');
        $deleteWhereCompany('pagos_compra');
        $deleteWhereCompany('compra_detalles');
        $deleteWhereCompany('compras');
        $deleteWhereCompany('ordenes_compra');

        $deleteWhereCompany('traspasos_caja');
        $deleteWhereCompany('cierres_caja');
        $deleteWhereCompany('movimientos_caja');
        $deleteWhereCompany('devoluciones');
        $deleteWhereCompany('factura_detalles');
        $deleteWhereCompany('facturas');
        $deleteWhereCompany('venta_pagos');
        $deleteWhereCompany('venta_detalles');
        $deleteWhereCompany('ventas');
        $deleteWhereCompany('aperturas_caja');
        $deleteWhereCompany('cajas');
        $deleteWhereCompany('clientes');

        $deleteWhereCompany('ajustes_inventario');
        $deleteWhereCompany('movimientos_inventario');
        $deleteWhereCompany('inventario');
        $deleteWhereCompany('producto_variantes');
        $deleteWhereCompany('productos');
        $deleteWhereCompany('impuestos');
        $deleteWhereCompany('proveedores');
        $deleteWhereCompany('marcas');
        $deleteWhereCompany('categorias');

        $deleteWhereCompany('impresoras');
        $deleteWhereCompany('resoluciones_dian');
        $deleteWhereCompany('numeraciones_documentos');
        $deleteWhereCompany('unidades_medida');
        $deleteWhereCompany('metodos_pago');
        $deleteWhereCompany('configuracion_empresa');
        $deleteWhereCompany('suscripciones');

        if ($tableExists('usuario_empresa')) {
            DB::table('usuario_empresa')->where('empresa_id', $empresaId)->delete();
        }

        if ($tableExists('usuarios')) {
            DB::table('usuarios')
                ->where('empresa_id', $empresaId)
                ->update([
                    'empresa_id' => null,
                    'sucursal_id' => null,
                    'activo' => 0,
                    'updated_at' => $now,
                ]);
        }

        if ($tableExists('sucursales')) {
            DB::table('sucursales')->where('empresa_id', $empresaId)->delete();
        }
    }

    private function ensureEmpresaAccess(Empresa $empresa): void
    {
        if (has_permission('superadmin.acceso')) {
            return;
        }

        $user = auth_user();
        $empresaIds = $user ? $user->accessibleEmpresaIds() : [];

        abort_unless(in_array((int) $empresa->id, $empresaIds, true), 403, 'No tienes acceso a esta empresa.');
    }
}
