<?php

namespace App\Http\Controllers\Admin\Odoo;

use App\Http\Controllers\Controller;
use App\OdooSystem;
use App\OdooJvSection;
use App\OdooJvStep;
use App\OdooJvEntry;
use App\OdooGlCode;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\DB;

class OdooDashboardController extends Controller
{
    private $request;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    // ── Dashboard Page ────────────────────────────────────────────────────────

    public function index()
    {
        return view('admin.odoo.dashboard');
    }

    // ── Systems ───────────────────────────────────────────────────────────────

    public function getSystems()
    {
        $systems = OdooSystem::withCount(['sections as steps_count' => function ($q) {
            $q->join('odoo_jv_steps', 'odoo_jv_steps.section_id', '=', 'odoo_jv_sections.id');
        }])->orderBy('id')->get();

        return response()->json(['status' => 'success', 'data' => $systems]);
    }

    public function createSystem()
    {
        $name = trim($this->request->get('name'));
        $desc = trim($this->request->get('description', ''));

        if (!$name) {
            return response()->json(['status' => 'error', 'message' => 'name is required'], 400);
        }

        $slug = Str::slug($name);
        if (OdooSystem::where('slug', $slug)->exists()) {
            return response()->json(['status' => 'error', 'message' => 'A system with this name already exists'], 409);
        }

        $system = OdooSystem::create([
            'name'        => $name,
            'slug'        => $slug,
            'description' => $desc,
            'is_active'   => true,
        ]);

        return response()->json(['status' => 'success', 'data' => $system], 201);
    }

    public function updateSystem($id)
    {
        $system = OdooSystem::find($id);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $system->name        = trim($this->request->get('name', $system->name));
        $system->description = trim($this->request->get('description', $system->description));
        $system->is_active   = $this->request->has('is_active') ? (bool)$this->request->get('is_active') : $system->is_active;
        $system->save();

        return response()->json(['status' => 'success', 'data' => $system]);
    }

    public function deleteSystem($id)
    {
        $system = OdooSystem::find($id);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }
        $system->delete();
        return response()->json(['status' => 'success', 'message' => 'System deleted']);
    }

    // ── Sections ──────────────────────────────────────────────────────────────

    public function getSections($systemId)
    {
        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        // NEW: Support partner filtering
        $partnerId = $this->request->get('partner_id');
        $partnerType = $this->request->get('partner_type', $system->slug);

        $query = OdooJvSection::where('system_id', $systemId);

        if ($partnerId) {
            // Get partner-specific sections
            $query->where('partner_id', $partnerId)
                  ->where('partner_type', $partnerType);
        } else {
            // Get system default sections
            $query->whereNull('partner_id');
        }

        $sections = $query->withCount('steps')
            ->with(['steps' => function($q) use ($partnerId, $partnerType) {
                if ($partnerId) {
                    $q->where('partner_id', $partnerId)->where('partner_type', $partnerType);
                } else {
                    $q->whereNull('partner_id');
                }
                $q->withCount('entries')->orderBy('sort_order');
            }])
            ->orderBy('sort_order')
            ->get();

        return response()->json(['status' => 'success', 'data' => $sections, 'system' => $system]);
    }

    public function createSection($systemId)
    {
        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $name = trim($this->request->get('name'));
        if (!$name) {
            return response()->json(['status' => 'error', 'message' => 'name is required'], 400);
        }

        // NEW: Support partner-specific sections
        $partnerId = $this->request->get('partner_id');
        $partnerType = $this->request->get('partner_type', $system->slug);

        $maxOrderQuery = OdooJvSection::where('system_id', $systemId);
        if ($partnerId) {
            $maxOrderQuery->where('partner_id', $partnerId)->where('partner_type', $partnerType);
        } else {
            $maxOrderQuery->whereNull('partner_id');
        }
        $maxOrder = $maxOrderQuery->max('sort_order') ?? 0;

        $section = OdooJvSection::create([
            'system_id'   => $systemId,
            'name'        => $name,
            'sort_order'  => $maxOrder + 1,
            'partner_id'  => $partnerId,
            'partner_type'=> $partnerId ? $partnerType : null,
        ]);

        return response()->json(['status' => 'success', 'data' => $section], 201);
    }

    public function updateSection($id)
    {
        $section = OdooJvSection::find($id);
        if (!$section) {
            return response()->json(['status' => 'error', 'message' => 'Section not found'], 404);
        }

        $section->name       = trim($this->request->get('name', $section->name));
        $section->sort_order = $this->request->get('sort_order', $section->sort_order);
        $section->save();

        return response()->json(['status' => 'success', 'data' => $section]);
    }

    public function deleteSection($id)
    {
        $section = OdooJvSection::find($id);
        if (!$section) {
            return response()->json(['status' => 'error', 'message' => 'Section not found'], 404);
        }
        $section->delete();
        return response()->json(['status' => 'success', 'message' => 'Section deleted']);
    }

    // ── Steps ─────────────────────────────────────────────────────────────────

    public function getSteps($sectionId)
    {
        $section = OdooJvSection::with('system')->find($sectionId);
        if (!$section) {
            return response()->json(['status' => 'error', 'message' => 'Section not found'], 404);
        }

        // NEW: Support partner filtering (inherited from section)
        $partnerId = $section->partner_id;
        $partnerType = $section->partner_type;

        $query = OdooJvStep::where('section_id', $sectionId);

        if ($partnerId) {
            $query->where('partner_id', $partnerId)->where('partner_type', $partnerType);
        } else {
            $query->whereNull('partner_id');
        }

        $steps = $query->withCount('entries')
            ->orderBy('sort_order')
            ->get();

        return response()->json(['status' => 'success', 'data' => $steps, 'section' => $section]);
    }

    public function createStep($sectionId)
    {
        $section = OdooJvSection::find($sectionId);
        if (!$section) {
            return response()->json(['status' => 'error', 'message' => 'Section not found'], 404);
        }

        $stepKey = trim($this->request->get('step_key'));
        if (!$stepKey) {
            return response()->json(['status' => 'error', 'message' => 'step_key is required'], 400);
        }

        // NEW: step_key must be unique within system + partner combination
        $existsQuery = OdooJvStep::whereHas('section', function($q) use ($section) {
            $q->where('system_id', $section->system_id);
            if ($section->partner_id) {
                $q->where('partner_id', $section->partner_id)->where('partner_type', $section->partner_type);
            } else {
                $q->whereNull('partner_id');
            }
        })->where('step_key', $stepKey);

        if ($existsQuery->exists()) {
            return response()->json(['status' => 'error', 'message' => 'step_key already exists in this configuration'], 409);
        }

        $maxOrder = OdooJvStep::where('section_id', $sectionId)->max('sort_order') ?? 0;

        $step = OdooJvStep::create([
            'section_id'   => $sectionId,
            'step_key'     => $stepKey,
            'label'        => trim($this->request->get('label', $stepKey)),
            'voucher_type' => trim($this->request->get('voucher_type', '')),
            'is_enabled'   => (bool)$this->request->get('is_enabled', true),
            'sort_order'   => $maxOrder + 1,
            'partner_id'   => $section->partner_id,
            'partner_type' => $section->partner_type,
        ]);

        return response()->json(['status' => 'success', 'data' => $step], 201);
    }

    public function updateStep($id)
    {
        $step = OdooJvStep::find($id);
        if (!$step) {
            return response()->json(['status' => 'error', 'message' => 'Step not found'], 404);
        }

        $step->label        = trim($this->request->get('label', $step->label));
        $step->voucher_type = trim($this->request->get('voucher_type', $step->voucher_type));
        $step->is_enabled   = $this->request->has('is_enabled') ? (bool)$this->request->get('is_enabled') : $step->is_enabled;
        $step->sort_order   = $this->request->get('sort_order', $step->sort_order);
        $step->save();

        return response()->json(['status' => 'success', 'data' => $step]);
    }

    public function deleteStep($id)
    {
        $step = OdooJvStep::find($id);
        if (!$step) {
            return response()->json(['status' => 'error', 'message' => 'Step not found'], 404);
        }
        $step->delete();
        return response()->json(['status' => 'success', 'message' => 'Step deleted']);
    }

    // ── Entries ───────────────────────────────────────────────────────────────

    public function getEntries($stepId)
    {
        $step = OdooJvStep::with(['section.system'])->find($stepId);
        if (!$step) {
            return response()->json(['status' => 'error', 'message' => 'Step not found'], 404);
        }

        $entries = OdooJvEntry::where('step_id', $stepId)->orderBy('sequence')->get();

        return response()->json(['status' => 'success', 'data' => $entries, 'step' => $step]);
    }

    public function createEntry($stepId)
    {
        $step = OdooJvStep::find($stepId);
        if (!$step) {
            return response()->json(['status' => 'error', 'message' => 'Step not found'], 404);
        }

        $type    = $this->request->get('type', 'Dr');
        $account = trim($this->request->get('account', ''));
        $glCode  = trim($this->request->get('gl_code', ''));

        if (!in_array($type, ['Dr', 'Cr'])) {
            return response()->json(['status' => 'error', 'message' => 'type must be Dr or Cr'], 400);
        }

        $maxSeq  = OdooJvEntry::where('step_id', $stepId)->max('sequence') ?? 0;

        $entry = OdooJvEntry::create([
            'step_id'            => $stepId,
            'type'               => $type,
            'account'            => $account,
            'gl_code'            => $glCode,
            'sequence'           => (int)$this->request->get('sequence', $maxSeq + 1),
            'summary'            => trim($this->request->get('summary', '')),
            'amount_field'       => trim($this->request->get('amount_field', '')) ?: null,
            'is_balancing_credit'=> (bool)$this->request->get('is_balancing_credit', false),
        ]);

        return response()->json(['status' => 'success', 'data' => $entry], 201);
    }

    public function updateEntry($id)
    {
        $entry = OdooJvEntry::find($id);
        if (!$entry) {
            return response()->json(['status' => 'error', 'message' => 'Entry not found'], 404);
        }

        $type = $this->request->get('type', $entry->type);
        if (!in_array($type, ['Dr', 'Cr'])) {
            return response()->json(['status' => 'error', 'message' => 'type must be Dr or Cr'], 400);
        }

        $entry->type               = $type;
        $entry->account            = trim($this->request->get('account', $entry->account));
        $entry->gl_code            = trim($this->request->get('gl_code', $entry->gl_code));
        $entry->sequence           = (int)$this->request->get('sequence', $entry->sequence);
        $entry->summary            = trim($this->request->get('summary', $entry->summary));
        $amountField               = trim($this->request->get('amount_field', $entry->amount_field ?? ''));
        $entry->amount_field       = $amountField ?: null;
        $entry->is_balancing_credit= $this->request->has('is_balancing_credit')
            ? (bool)$this->request->get('is_balancing_credit')
            : $entry->is_balancing_credit;
        $entry->save();

        return response()->json(['status' => 'success', 'data' => $entry]);
    }

    public function deleteEntry($id)
    {
        $entry = OdooJvEntry::find($id);
        if (!$entry) {
            return response()->json(['status' => 'error', 'message' => 'Entry not found'], 404);
        }
        $entry->delete();
        return response()->json(['status' => 'success', 'message' => 'Entry deleted']);
    }

    // ── Partner Management ────────────────────────────────────────────────────

    public function getSystemPartners($systemId)
    {
        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $partners = $system->getPartners()->map(function($partner) {
            $displayName = $partner->name;
            $isSubPartner = !empty($partner->sub_partner_id);
            if ($isSubPartner && \Schema::hasTable('partner_data')) {
                $parentName = \DB::table('partner_data')->where('id', $partner->sub_partner_id)->value('name');
                if ($parentName) {
                    $displayName = $parentName . ' → ' . $partner->name;
                }
            }
            return [
                'id' => $partner->id,
                'name' => $partner->name,
                'display_name' => $displayName,
                'is_sub_partner' => $isSubPartner,
            ];
        });
        return response()->json(['status' => 'success', 'data' => $partners]);
    }

    public function checkPartnerConfig($systemId, $partnerId)
    {
        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $partnerType = $this->request->get('partner_type', $system->slug);

        // Check if partner has any sections
        $hasConfig = OdooJvSection::where('system_id', $systemId)
            ->where('partner_id', $partnerId)
            ->where('partner_type', $partnerType)
            ->exists();

        return response()->json([
            'status' => 'success',
            'has_config' => $hasConfig,
            'partner_id' => $partnerId,
            'partner_type' => $partnerType
        ]);
    }

    public function deletePartnerConfig($systemId, $partnerId)
    {
        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $partnerType = $this->request->get('partner_type', $system->slug);

        DB::beginTransaction();
        try {
            // Get all sections for this partner
            $sections = OdooJvSection::where('system_id', $systemId)
                ->where('partner_id', $partnerId)
                ->where('partner_type', $partnerType)
                ->get();

            foreach ($sections as $section) {
                // Get all steps
                $steps = OdooJvStep::where('section_id', $section->id)->get();
                
                foreach ($steps as $step) {
                    // Delete entries
                    OdooJvEntry::where('step_id', $step->id)->delete();
                }
                
                // Delete steps
                OdooJvStep::where('section_id', $section->id)->delete();
            }

            // Delete sections
            OdooJvSection::where('system_id', $systemId)
                ->where('partner_id', $partnerId)
                ->where('partner_type', $partnerType)
                ->delete();

            DB::commit();

            return response()->json([
                'status' => 'success',
                'message' => 'Partner configuration deleted successfully'
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'status' => 'error',
                'message' => 'Failed to delete partner configuration: ' . $e->getMessage()
            ], 500);
        }
    }

    public function cloneConfigToPartner()
    {
        $systemId = $this->request->get('system_id');
        $partnerId = $this->request->get('partner_id');

        $system = OdooSystem::find($systemId);
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        if (!$partnerId) {
            return response()->json(['status' => 'error', 'message' => 'partner_id is required'], 400);
        }

        $partnerType = $this->request->get('partner_type', $system->slug);

        // Check if partner already has config
        $hasConfig = OdooJvSection::where('system_id', $systemId)
            ->where('partner_id', $partnerId)
            ->where('partner_type', $partnerType)
            ->exists();

        if ($hasConfig) {
            return response()->json([
                'status' => 'error',
                'message' => 'Partner already has configuration. Delete existing config first to re-clone.'
            ], 409);
        }

        DB::beginTransaction();
        try {
            // Get all system default sections
            $systemSections = OdooJvSection::where('system_id', $systemId)
                ->whereNull('partner_id')
                ->orderBy('sort_order')
                ->get();

            if ($systemSections->isEmpty()) {
                DB::rollBack();
                return response()->json([
                    'status' => 'error',
                    'message' => 'No system default configuration found to clone'
                ], 404);
            }

            $clonedCount = ['sections' => 0, 'steps' => 0, 'entries' => 0];

            foreach ($systemSections as $section) {
                // Clone section
                $newSection = OdooJvSection::create([
                    'system_id' => $systemId,
                    'name' => $section->name,
                    'sort_order' => $section->sort_order,
                    'partner_id' => $partnerId,
                    'partner_type' => $partnerType,
                ]);
                $clonedCount['sections']++;

                // Get all steps for this section
                $steps = OdooJvStep::where('section_id', $section->id)
                    ->orderBy('sort_order')
                    ->get();

                foreach ($steps as $step) {
                    // Clone step
                    $newStep = OdooJvStep::create([
                        'section_id' => $newSection->id,
                        'step_key' => $step->step_key,
                        'label' => $step->label,
                        'voucher_type' => $step->voucher_type,
                        'is_enabled' => $step->is_enabled,
                        'sort_order' => $step->sort_order,
                        'partner_id' => $partnerId,
                        'partner_type' => $partnerType,
                    ]);
                    $clonedCount['steps']++;

                    // Get all entries for this step
                    $entries = OdooJvEntry::where('step_id', $step->id)
                        ->orderBy('sequence')
                        ->get();

                    foreach ($entries as $entry) {
                        // Clone entry
                        OdooJvEntry::create([
                            'step_id' => $newStep->id,
                            'type' => $entry->type,
                            'account' => $entry->account,
                            'gl_code' => $entry->gl_code,
                            'sequence' => $entry->sequence,
                            'summary' => $entry->summary,
                            'amount_field' => $entry->amount_field,
                            'is_balancing_credit' => $entry->is_balancing_credit,
                        ]);
                        $clonedCount['entries']++;
                    }
                }
            }

            DB::commit();

            return response()->json([
                'status' => 'success',
                'message' => 'Configuration cloned successfully',
                'cloned' => $clonedCount
            ], 201);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'status' => 'error',
                'message' => 'Failed to clone configuration: ' . $e->getMessage()
            ], 500);
        }
    }

    // ── Full config export (for OdooController getJvSteps) ───────────────────

    public function getFullConfig($systemSlug)
    {
        $system = OdooSystem::where('slug', $systemSlug)->where('is_active', true)->first();
        if (!$system) {
            return response()->json(['status' => 'error', 'message' => 'System not found'], 404);
        }

        $partnerId = $this->request->get('partner_id');
        $partnerType = $this->request->get('partner_type', $system->slug);

        $query = OdooJvSection::where('system_id', $system->id);
        if ($partnerId) {
            $query->where('partner_id', $partnerId)->where('partner_type', $partnerType);
        } else {
            $query->whereNull('partner_id');
        }

        $data = $query->with(['steps' => function($q) use ($partnerId, $partnerType) {
                if ($partnerId) {
                    $q->where('partner_id', $partnerId)->where('partner_type', $partnerType);
                } else {
                    $q->whereNull('partner_id');
                }
                $q->orderBy('sort_order');
            }, 'steps.entries' => function($q) {
                $q->orderBy('sequence');
            }])
            ->orderBy('sort_order')
            ->get();

        return response()->json(['status' => 'success', 'data' => $data, 'system' => $system]);
    }

    // ── GL Code Master ────────────────────────────────────────────────────────

    public function getGlCodes()
    {
        $query = OdooGlCode::query();

        $search = trim($this->request->get('search', ''));
        if ($search !== '') {
            $query->where(function ($q) use ($search) {
                $q->where('gl_code', 'like', "%{$search}%")
                  ->orWhere('gl_name', 'like', "%{$search}%")
                  ->orWhere('ledger_name', 'like', "%{$search}%");
            });
        }

        if ($this->request->has('active_only') && $this->request->get('active_only') == '1') {
            $query->where('is_active', true);
        }

        $glCodes = $query->orderBy('gl_code', 'asc')->get();

        return response()->json(['status' => 'success', 'data' => $glCodes]);
    }

    public function createGlCode()
    {
        $glCode     = trim($this->request->get('gl_code', ''));
        $ledgerName = trim($this->request->get('ledger_name', ''));
        $glName     = trim($this->request->get('gl_name', ''));
        $isActive   = $this->request->has('is_active') ? (bool)$this->request->get('is_active') : true;

        if (!$glCode) {
            return response()->json(['status' => 'error', 'message' => 'GL Code is required'], 400);
        }
        if (!$ledgerName) {
            return response()->json(['status' => 'error', 'message' => 'Ledger Name is required'], 400);
        }
        if (!$glName) {
            return response()->json(['status' => 'error', 'message' => 'GL Name is required'], 400);
        }

        if (OdooGlCode::where('gl_code', $glCode)->exists()) {
            return response()->json(['status' => 'error', 'message' => 'A record with GL Code "' . $glCode . '" already exists'], 409);
        }

        $record = OdooGlCode::create([
            'gl_code'     => $glCode,
            'ledger_name' => $ledgerName,
            'gl_name'     => $glName,
            'is_active'   => $isActive,
        ]);

        return response()->json(['status' => 'success', 'data' => $record], 201);
    }

    public function updateGlCode($id)
    {
        $record = OdooGlCode::find($id);
        if (!$record) {
            return response()->json(['status' => 'error', 'message' => 'GL Code record not found'], 404);
        }

        $glCode     = trim($this->request->get('gl_code', $record->gl_code));
        $ledgerName = trim($this->request->get('ledger_name', $record->ledger_name));
        $glName     = trim($this->request->get('gl_name', $record->gl_name));

        if (!$glCode) {
            return response()->json(['status' => 'error', 'message' => 'GL Code is required'], 400);
        }
        if (!$ledgerName) {
            return response()->json(['status' => 'error', 'message' => 'Ledger Name is required'], 400);
        }
        if (!$glName) {
            return response()->json(['status' => 'error', 'message' => 'GL Name is required'], 400);
        }

        if (OdooGlCode::where('gl_code', $glCode)->where('id', '!=', $id)->exists()) {
            return response()->json(['status' => 'error', 'message' => 'Another record with GL Code "' . $glCode . '" already exists'], 409);
        }

        $record->gl_code     = $glCode;
        $record->ledger_name = $ledgerName;
        $record->gl_name     = $glName;
        if ($this->request->has('is_active')) {
            $record->is_active = (bool)$this->request->get('is_active');
        }
        $record->save();

        return response()->json(['status' => 'success', 'data' => $record]);
    }

    public function deleteGlCode($id)
    {
        $record = OdooGlCode::find($id);
        if (!$record) {
            return response()->json(['status' => 'error', 'message' => 'GL Code record not found'], 404);
        }

        $isUsed = OdooJvEntry::where('gl_code', $record->gl_code)->exists();
        if ($isUsed) {
            $record->is_active = false;
            $record->save();
            return response()->json(['status' => 'success', 'message' => 'GL Code is used by existing entries; deactivated instead of deleted.']);
        }

        $record->delete();
        return response()->json(['status' => 'success', 'message' => 'GL Code deleted successfully']);
    }
}
