<?php

namespace App\Http\Controllers;

use App\Models\Process;
use App\Models\Department;
use App\Models\Item;
use App\Models\ItemDetail;
use App\Models\ItemUnit;
use App\Models\DeleteLog;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\QueryException;

class ProcessController extends Controller
{
    public function index(): JsonResponse
    {
        try {
            $processes = Process::with(['departmentInfo', 'resultItem'])
                ->orderBy('process_code')
                ->get();
            $items = Item::get();
            return response()->json(["processes" => $processes,"items" => $items, "role" => $this->getRole()]);
        } catch (\Exception $e) {
            Log::error('Failed to fetch processes', ['error' => $e->getMessage(), 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Failed to fetch processes'], 500);
        }
    }

    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'process_code' => 'required|string|max:50|unique:process,process_code',
            'process_name' => 'required|string|max:255',
            'department' => 'required|exists:department,department_code',
            'notes' => 'nullable|string|max:255',
            'input_item_id' => 'required|json',
            'output_item_id' => 'required|json',
            'labor_id' => 'nullable',
            'machine_id' => 'nullable',
            'material_loss' => 'required|numeric',
            'standard_time' => 'required|numeric',
            'conversion_ratio' => 'required|numeric',
            'result_item_id' => 'nullable|exists:items,id',
            'tariff_reject' => 'nullable|numeric',
            'is_top' => 'nullable|boolean',
            'is_casing' => 'nullable|boolean'
        ]);

        try {
            DB::beginTransaction();

            $process = Process::create([
                'process_code' => $request->process_code,
                'process_name' => $request->process_name,
                'department' => $request->department,
                'notes' => $request->notes,
                'qty_set' => $request->qty_set,
                'input_item_id' => $request->input_item_id,
                'output_item_id' => $request->output_item_id,
                'labor_id' => $request->labor_id,
                'machine_id' => $request->machine_id,
                'material_loss' => $request->material_loss,
                'standard_time' => $request->standard_time,
                'conversion_ratio' => $request->conversion_ratio,
                'result_item_id' => $request->result_item_id,
                'tariff_reject' => $request->tariff_reject,
                'is_top' => $request->is_top ?? false,
                'is_casing' => $request->is_casing ?? false,
                'created_by' => auth()->id(),
                'updated_by' => auth()->id(),
            ]);

            DB::commit();

            $process->load(['createdBy', 'updatedBy']);
            return response()->json($process, 201);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to create process', ['error' => $e->getMessage(), 'process_code' => $request->process_code, 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Failed to create process: ' . $e->getMessage()], 500);
        }
    }

    public function show($id): JsonResponse
    {
        try {
            $process = Process::with(['createdBy', 'updatedBy'])
                ->where('id', $id)
                ->firstOrFail();
            return response()->json($process);
        } catch (\Exception $e) {
            Log::error('Failed to fetch process', ['id' => $id, 'error' => $e->getMessage(), 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Process not found'], 404);
        }
    }

    public function update(Request $request, $id): JsonResponse
    {
        $validated = $request->validate([
            'process_name' => 'required|string|max:255',
            'department' => 'required|exists:department,department_code',
            'notes' => 'nullable|string|max:255',
            'input_item_id' => 'required|json',
            'output_item_id' => 'required|json',
            'labor_id' => 'nullable',
            'machine_id' => 'nullable',
            'material_loss' => 'required|numeric',
            'standard_time' => 'required|numeric',
            'conversion_ratio' => 'required|numeric',
            'result_item_id' => 'nullable|exists:items,id',
            'tariff_reject' => 'nullable|numeric',
            'is_top' => 'nullable|boolean',
            'is_casing' => 'nullable|boolean'
        ]);

        try {
            DB::beginTransaction();

            $process = Process::where('id', $id)->firstOrFail();

            $process->update([
                'process_name' => $request->process_name,
                'department' => $request->department,
                'notes' => $request->notes,
                'qty_set' => $request->qty_set,
                'input_item_id' => $request->input_item_id,
                'output_item_id' => $request->output_item_id,
                'labor_id' => $request->labor_id,
                'machine_id' => $request->machine_id,
                'material_loss' => $request->material_loss,
                'standard_time' => $request->standard_time,
                'conversion_ratio' => $request->conversion_ratio,
                'result_item_id' => $request->result_item_id,
                'tariff_reject' => $request->tariff_reject,
                'is_top' => $request->is_top ?? false,
                'is_casing' => $request->is_casing ?? false,
                'updated_by' => auth()->id(),
            ]);

            DB::commit();

            $process->load(['createdBy', 'updatedBy']);
            return response()->json($process);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to update process', ['id' => $id, 'error' => $e->getMessage(), 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Failed to update process: ' . $e->getMessage()], 500);
        }
    }

    public function destroy(Request $request, $id): JsonResponse
    {
        try {
            DB::beginTransaction();

            $process = Process::where('id', $id)->firstOrFail();
            $process->delete();

            DeleteLog::create([
                'document_number' => $process->process_code,
                'document_date' => now(),
                'delete_notes' => $request->delete_notes ?? 'No notes provided',
                'company_code' => null,
                'department_code' => $process->department,
                'deleted_by' => Auth::check() ? Auth::user()->name : 'system',
                'type' => 'Master Process',
            ]);

            DB::commit();
            return response()->json(null, 204);
        } catch (QueryException $e) {
            DB::rollBack();
            Log::error('Failed to delete process due to query exception', ['id' => $id, 'error' => $e->getMessage(), 'user_id' => Auth::id()]);
            if ($e->getCode() === '23000') {
                return response()->json(['error' => 'Cannot delete process because it is being used in other records'], 422);
            }
            return response()->json(['error' => 'Failed to delete process'], 500);
        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Failed to delete process', ['id' => $id, 'error' => $e->getMessage(), 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Failed to delete process'], 500);
        }
    }

    public function getMasterData(): JsonResponse
    {
        try {
            $user = Auth::user();
            $departmentIds = [];

            if ($user && $user->default_department_id) {
                $decodedDepartments = json_decode($user->default_department_id, true);
                if (is_array($decodedDepartments)) {
                    $departmentIds = array_column($decodedDepartments, 'department_id');
                }
            }

            $itemsQuery = Item::query();

            if (!empty($departmentIds)) {
                $itemsQuery->whereHas('warehouse', function ($query) use ($departmentIds) {
                    $query->whereIn('department', $departmentIds);
                });
            } else {
                $itemsQuery->whereRaw('1 = 0');
            }

            $data = [
                'departments' => Department::orderBy('department_code')->get(),
                'items' => $itemsQuery->orderBy('item_code')->get(),
                'item_details' => ItemDetail::orderBy('item_id')->get(),
                'item_units' => ItemUnit::orderBy('unit_id')->get(),
                'role' => $this->getRole()
            ];

            return response()->json($data);

        } catch (\Exception $e) {
            Log::error('Failed to fetch master data', ['error' => $e->getMessage(), 'user_id' => Auth::id()]);
            return response()->json(['error' => 'Failed to fetch master data'], 500);
        }
    }
}
