<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Company;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class CompanyController extends Controller
{
    public function index(Request $request)
    {
        $user = $request->user();

        $query = Company::withCount(['employees', 'departments', 'users']);

        if (!$request->has('all') && !$user->isSuperAdmin()) {
            $query->where('id', $user->company_id);
        }

        $companies = $query->when($request->search, function ($q) use ($request) {
            $q->where('name', 'like', "%{$request->search}%")
              ->orWhere('email', 'like', "%{$request->search}%");
        })
        ->when($request->status, function ($q) use ($request) {
            $q->where('status', $request->status);
        })
        ->orderBy($request->get('sort_by', 'created_at'), $request->get('sort_order', 'desc'))
        ->paginate($request->get('per_page', 15));

        // Always calculate net_profit from monthly financials for consistency
        $companies->getCollection()->transform(function ($company) {
            $mfin = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
            $company->net_profit = (float) $mfin->net_profit;
            return $company;
        });

        return response()->json($companies);
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'nullable|email|unique:companies,email',
            'phone' => 'nullable|string|max:20',
            'address' => 'nullable|string',
            'industry' => 'nullable|string|max:255',
            'website' => 'nullable|url',
            'description' => 'nullable|string',
            'established_date' => 'nullable|date',
            'registration_number' => 'nullable|string|max:255',
            'tax_id' => 'nullable|string|max:255',
            'logo' => 'nullable|image|max:2048',
        ]);

    // Prevent clients from setting is_holding_company via API payloads.
    // The system's single holding company is managed via Company::systemHolding().
    $data = $request->except('logo', 'is_holding_company');
        $data['slug'] = Str::slug($request->name);

        if ($request->hasFile('logo')) {
            $data['logo'] = $request->file('logo')->store('logos', 'public');
        }

        $company = Company::create($data);

        activity()
            ->performedOn($company)
            ->log('Company created');

        return response()->json([
            'company' => $company,
            'message' => 'Company created successfully',
        ], 201);
    }

    public function show($id, Request $request)
    {
        $user = $request->user();

        $company = Company::withCount(['employees', 'departments', 'users'])
            ->findOrFail($id);

        if (!$user->canAccessCompany($id)) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        return response()->json(array_merge($company->toArray(), [
            'employee_count' => $company->employees_count,
            'revenue'        => (function() use ($company) {
                $mfin = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
                return (float) $mfin->revenue;
            })(),
            'expenses'       => (function() use ($company) {
                $mfin = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
                return (float) $mfin->expenses;
            })(),
            'net_profit'     => (function () use ($company) {
                // Always calculate from monthly financials for consistency
                $mfin = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
                return (float) $mfin->net_profit;
            })(),
            'cash_balance'   => (float)($company->getAttributes()['cash_balance'] ?? 0),
            'total_assets'   => (float)($company->getAttributes()['total_assets'] ?? 0),
            'total_liabilities' => (float)($company->getAttributes()['total_liabilities'] ?? 0),
            'credit_score'   => (int)($company->getAttributes()['credit_score'] ?? 0),
            'runway_days'    => (int)($company->getAttributes()['runway_days'] ?? 0),
            'profit_margin'  => (function() use ($company) {
                $mfin = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
                $revenue = (float) $mfin->revenue;
                $netProfit = (float) $mfin->net_profit;
                return $revenue > 0 ? round(($netProfit / $revenue) * 100, 1) : 0;
            })(),
            'health_status'  => $company->getAttributes()['health_status'] ?? 'good',
        ]));
    }

    public function update(Request $request, $id)
    {
        $user = $request->user();

        if (!$user->canAccessCompany($id) && !$user->isCompanyAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $company = Company::findOrFail($id);

        $request->validate([
            'name' => 'sometimes|string|max:255',
            'email' => 'sometimes|nullable|email|unique:companies,email,' . $id,
            'phone' => 'sometimes|nullable|string|max:20',
            'address' => 'sometimes|nullable|string',
            'industry' => 'sometimes|nullable|string|max:255',
            'website' => 'sometimes|nullable|url',
            'description' => 'sometimes|nullable|string',
            'status' => 'sometimes|in:active,inactive,suspended',
            'established_date' => 'sometimes|nullable|date',
            'registration_number' => 'sometimes|nullable|string|max:255',
            'tax_id' => 'sometimes|nullable|string|max:255',
            'logo' => 'sometimes|nullable|image|max:2048',
        ]);

    // Prevent clients from setting is_holding_company via API payloads.
    // Only the system may create the holding company via Company::systemHolding().
    $data = $request->except('logo', 'is_holding_company');

        if ($request->hasFile('logo')) {
            if ($company->logo) {
                Storage::disk('public')->delete($company->logo);
            }
            $data['logo'] = $request->file('logo')->store('logos', 'public');
        }

        $company->update($data);

        activity()
            ->performedOn($company)
            ->log('Company updated');

        return response()->json([
            'company' => $company->fresh(),
            'message' => 'Company updated successfully',
        ]);
    }

    public function destroy($id, Request $request)
    {
        $user = $request->user();

        if (!$user->isSuperAdmin()) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $company = Company::findOrFail($id);

        if ($company->logo) {
            Storage::disk('public')->delete($company->logo);
        }

        $company->delete();

        activity()
            ->performedOn($company)
            ->log('Company deleted');

        return response()->json(['message' => 'Company deleted successfully']);
    }

    public function statistics($id, Request $request)
    {
        $user = $request->user();

        if (!$user->canAccessCompany($id)) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $company = Company::findOrFail($id);
        // Read raw row — bypasses Eloquent casts and cached attributes
        $fin = DB::table('companies')->where('id', $company->id)->first();

        // ── Financial KPIs ─────────────────────────────────────────
        $revenue   = isset($fin->revenue) && $fin->revenue !== null ? (float)$fin->revenue : 0;
        $storedExp = isset($fin->expenses_manual) && $fin->expenses_manual !== null ? (float)$fin->expenses_manual : null;
        $expenses  = $storedExp !== null
            ? $storedExp
            : (float) \App\Models\Expense::where('company_id', $company->id)
                ->whereNotIn('status', ['rejected', 'cancelled'])
                ->sum('amount');
        $cash       = isset($fin->cash_balance) && $fin->cash_balance !== null ? (float)$fin->cash_balance : 0;
        $assetSum   = (float) DB::table('company_assets')
            ->where('company_id', $company->id)->where('status', 'active')->sum('current_value');
        $storedAssets = isset($fin->total_assets) && $fin->total_assets !== null ? (float)$fin->total_assets : 0;
        $assets     = $assetSum > 0 ? $assetSum : $storedAssets;
        $liab       = isset($fin->total_liabilities) && $fin->total_liabilities !== null ? (float)$fin->total_liabilities : 0;
        // Use monthly financial model for consistent net profit (includes staff loans in expenses)
        $mfin      = \App\Models\MonthlyCompanyFinancial::recalculateMonth($company->id, now()->format('Y-m'));
        $netProfit  = (float) $mfin->net_profit;
        $revenue    = (float) $mfin->revenue;
        $expenses   = (float) $mfin->expenses;
        $margin     = $revenue > 0 ? round(($netProfit / $revenue) * 100, 1) : 0;

        $financial = [
            'revenue'           => $revenue,
            'expenses'          => $expenses,
            'net_profit'        => $netProfit,
            'cash_balance'      => $cash,
            'total_assets'      => $assets,
            'total_liabilities' => $liab,
            'credit_score'      => (int)($fin->credit_score ?? 0),
            'runway_days'       => (int)($fin->runway_days ?? 0),
            'profit_margin'     => $margin,
            'health_status'     => $fin->health_status ?? 'good',
        ];

        // ── Revenue trend (6 months) ────────────────────────────────
        $mNames = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
        $revenueTrend = [];
        $invoiceTotalAll = 0;
        for ($i = 5; $i >= 0; $i--) {
            $m    = \Carbon\Carbon::now()->subMonths($i);
            $mS   = $m->copy()->startOfMonth();
            $mE   = $m->copy()->endOfMonth();
            $rv   = 0;
            try {
                $rv = (float) DB::table('invoices')
                    ->where('company_id', $company->id)
                    ->where('type', 'receivable')
                    ->whereBetween('invoice_date', [$mS, $mE])
                    ->whereIn('status', ['sent', 'viewed', 'partial', 'paid'])
                    ->sum('total_amount');
            } catch (\Exception $e) {}
            $invoiceTotalAll += $rv;
            $ex = (float) \App\Models\Expense::where('company_id', $company->id)
                ->whereBetween('expense_date', [$mS, $mE])
                ->whereNotIn('status', ['rejected', 'cancelled'])
                ->sum('amount');
            // Include payable invoices in expenses (money going out)
            $payableInv = (float) DB::table('invoices')
                ->where('company_id', $company->id)
                ->where('type', 'payable')
                ->whereBetween('invoice_date', [$mS, $mE])
                ->whereIn('status', ['sent', 'viewed', 'partial', 'paid'])
                ->sum('total_amount');
            // Include staff loan deductions in expenses for historical consistency
            $loanDed = (float) DB::table('staff_loan_deductions')
                ->join('staff_loans', 'staff_loan_deductions.staff_loan_id', '=', 'staff_loans.id')
                ->where('staff_loans.company_id', $company->id)
                ->whereBetween('staff_loan_deductions.due_date', [$mS, $mE])
                ->where('staff_loan_deductions.status', 'deducted')
                ->sum('staff_loan_deductions.deduction_amount');
            $totalExpenses = $ex + $payableInv + $loanDed;
            $revenueTrend[] = ['month' => $mNames[$m->month - 1], 'revenue' => (int)$rv, 'expenses' => (int)$totalExpenses, 'profit' => (int)($rv - $totalExpenses)];
        }
        // If no invoice data but company has stored revenue, spread it evenly
        if ($invoiceTotalAll === 0 && $revenue > 0) {
            $monthly = (int)($revenue / 12);
            $revenueTrend = array_map(fn($r) => array_merge($r, ['revenue' => $monthly, 'profit' => $monthly - $r['expenses']]), $revenueTrend);
        }

        // ── Expense breakdown by category ───────────────────────────
        $expenseBreakdown = [];
        try {
            $expRows = \App\Models\Expense::where('expenses.company_id', $company->id)
                ->whereNotIn('expenses.status', ['rejected', 'cancelled'])
                ->join('expense_categories', 'expenses.expense_category_id', '=', 'expense_categories.id')
                ->select('expense_categories.name as cat_name', 'expense_categories.color', DB::raw('SUM(expenses.amount) as total'))
                ->groupBy('cat_name', 'expense_categories.color')
                ->orderByDesc('total')->limit(8)->get();
            $expenseBreakdown = $expRows->map(fn($r) => ['name' => $r->cat_name, 'value' => (float)$r->total, 'color' => $r->color ?? '#2563EB'])->toArray();
        } catch (\Exception $e) {}
        if (empty($expenseBreakdown) && $expenses > 0) {
            $expenseBreakdown = [['name' => 'Expenses', 'value' => $expenses, 'color' => '#2563EB']];
        }

        // ── Asset distribution ──────────────────────────────────────
        $assetDist = [];
        try {
            $aRows = DB::table('company_assets')->where('company_id', $company->id)->where('status', 'active')
                ->select('category', DB::raw('SUM(current_value) as cv'), DB::raw('SUM(purchase_value) as pv'))
                ->groupBy('category')->orderByDesc('cv')->get();
            $assetDist = $aRows->map(fn($r) => ['category' => ucfirst(str_replace('_', ' ', $r->category)), 'current' => (int)$r->cv, 'target' => (int)$r->pv])->toArray();
        } catch (\Exception $e) {}

        $byType = $company->employees()
            ->selectRaw('employment_type, COUNT(*) as count')
            ->groupBy('employment_type')
            ->pluck('count', 'employment_type');

        $stats = [
            'total_employees'    => $company->employees()->count(),
            'active_employees'   => $company->employees()->where('status', 'active')->count(),
            'total_departments'  => $company->departments()->count(),
            'total_users'        => $company->users()->count(),
            'employment_types'   => [
                'full_time' => $byType['full_time'] ?? 0,
                'part_time' => $byType['part_time'] ?? 0,
                'contract'  => $byType['contract']  ?? 0,
            ],
            'financial'          => $financial,
            'revenue_trend'      => $revenueTrend,
            'expense_breakdown'  => $expenseBreakdown,
            'asset_distribution' => $assetDist,
            'employees_by_department' => $company->departments()->withCount('employees')->get()
                ->map(fn($d) => ['department' => $d->name, 'count' => $d->employees_count]),
            'monthly_hire_trend' => $company->employees()
                ->select('hire_date')->where('hire_date', '>=', now()->subMonths(6))->get()
                ->groupBy(fn($e) => $e->hire_date->format('Y-m'))
                ->map(fn($g, $ym) => ['month' => (new \DateTime($ym.'-01'))->format('M'), 'year_month' => $ym, 'count' => $g->count()])
                ->sortKeys()->values(),
            'recent_hires' => $company->employees()->with('department')->orderBy('hire_date', 'desc')->limit(25)->get()
                ->map(fn($e) => array_merge($e->toArray(), ['full_name' => $e->first_name.' '.$e->last_name])),
        ];

        return response()->json($stats);
    }
}
