<?php

namespace App\Http\Controllers\Admin\Odoo;

use App\Http\Controllers\Controller;
use Auth;
use Illuminate\Http\Request;
use App\PartnerData;
use Illuminate\Support\Facades\Log;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;

class OdooController extends Controller
{
    private $request;

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

    public static function registry(){
        return [
            [
                'name'    => 'Odoo Partners',
                'summary' => 'Manage Odoo partners configurations and details.',
                'url'     => '/admin/odoo',
            ],
            [
                'name'    => 'Odoo JVs',
                'summary' => 'Manage Odoo JVs configurations and details.',
                'url'     => '/admin/odoo/jvs',
            ],
            [
                'name'    => 'Odoo Dashboard',
                'summary' => 'Manage Odoo dashborad configurations and details.'
            ],
        ];
    }

    public function index()
    {
        $fromDate = $this->request->get('from_date');
        $toDate = $this->request->get('to_date');

        $query = PartnerData::with(['odooDetail', 'parent'])->whereNotNull('sub_partner_id');

        if ($fromDate) {
            $query->whereDate('created_at', '>=', $fromDate);
        }
        if ($toDate) {
            $query->whereDate('created_at', '<=', $toDate);
        }

        $partners = $query->orderBy('id', 'desc')->paginate(20);

        return view('admin.odoo.generate-odoo', compact('partners', 'fromDate', 'toDate'));
    }

    public function jvs()
    {
        $fromDate = $this->request->get('from_date', \Carbon\Carbon::now()->subWeek()->format('Y-m-d'));
        $toDate = $this->request->get('to_date', \Carbon\Carbon::now()->format('Y-m-d'));

        $query = \App\DaSystemData::query();

        if ($fromDate) {
            $query->whereDate('created_at', '>=', $fromDate);
        }
        if ($toDate) {
            $query->whereDate('created_at', '<=', $toDate);
        }

        $applications = $query->orderBy('id', 'desc')->paginate(20);

        $jvSteps = $this->getJvSteps();

        return view('admin.odoo.jvs', compact('applications', 'fromDate', 'toDate', 'jvSteps'));
    }

    public function createJv()
    {
        try {
            $applicationId = $this->request->get('application_id');
            $stepKey = $this->request->get('step_key');

            if (!$applicationId || !$stepKey) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'application_id and JV are required'
                ], 400);
            }

            $application = \App\DaSystemData::with('partner')->find($applicationId);
            if (!$application) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'DA System record not found'
                ], 404);
            }

            $partner = $application->partner;

            if ($partner) {
                $companyName = !empty($partner->company) ? $partner->company : ($partner->name ?? '');
                $partnerName = $partner->name ?? ($application->member_name ?? '');
                $partnerUniqueCode = strtoupper(substr(trim($partner->name), 0, 3)) . '-' . $partner->id;
            } else {
                $companyName = $application->member_name ?? '';
                $partnerName = $application->member_name ?? '';
                $partnerUniqueCode = strtoupper(substr(trim($application->member_name ?? 'CUST'), 0, 3)) . '-' . $application->id;
            }

            $txNo = "TXN_" . date('Ymd') . "_" . str_pad($applicationId, 3, '0', STR_PAD_LEFT);
            $postingDate = \Carbon\Carbon::now()->format('Y-m-d');
            $steps = $this->getJvSteps($stepKey);


            $lines = array_map(function ($step) use ($applicationId, $partnerName, $partnerUniqueCode, $application) {
                $line = [
                    "sequence"            => $step['sequence'],
                    "gl_code"             => $step['gl_code'],
                    "reference"           => "REF" . $applicationId,
                    "partner_name"        => $partnerName,
                    "partner_unique_code" => $partnerUniqueCode
                ];

                $line = array_merge($line, $this->calculateJvAmount($step['gl_code'], $application));

                return $line;
            }, $steps);

            $payload = [
                "transaction_number" => $txNo,
                "posting_date"       => $postingDate,
                "company_name"       => "BLACKSOIL CAPITAL PRIVATE LIMITED",
                "type"               => "payment",
                "lines"              => $lines
            ];

            $odooService = new \App\Odoo\OdooService();
            $apiResult = $odooService->createJvEntry($payload);

            $statusCode = $apiResult['http_code'];
            $responseData = is_array($apiResult['response']) ? $apiResult['response'] : json_decode($apiResult['response'], true);
            $body = is_string($apiResult['response']) ? $apiResult['response'] : json_encode($apiResult['response']);

            if ($statusCode >= 200 && $statusCode < 300) {
                return response()->json([
                    'status'  => 'success',
                    'message' => 'Successfully created JV in Odoo for JvKey ' . $stepKey,
                    'data'    => $responseData,
                ], $statusCode);
            } else {
                $errorMsg = 'Failed to create JV in Odoo';
                if (is_array($responseData) && isset($responseData['message'])) {
                    $errorMsg = $responseData['message'];
                }

                return response()->json([
                    'status'  => 'error',
                    'message' => $errorMsg,
                    'error'   => $responseData ?? $body,
                ], $statusCode);
            }

        } catch (\Exception $e) {
            Log::error('Odoo createJv Exception: ' . $e->getMessage(), [
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'status'  => 'error',
                'message' => 'An internal error occurred',
                'error'   => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Calculate JV amount based on GL code
     */
    private function calculateJvAmount($glCode, $application)
    {
        $glCode = (string)$glCode;

        if ($glCode === '136000') {
            // GL Code 136000: Loans and Advances
            return ['credit' => (float)($application->disbursement_amount ?? $application->principal_total ?? 0), 'debit' => 0];
        }
        if ($glCode === '133001') {
            return ['credit' => 0, 'debit' => 10000];
        }
        if ($glCode === '100201') {
            return ['credit' => 10000, 'debit' => 0];
        }

        return ['credit' => 0, 'debit' => 0];
    }

    public function createCustomer()
    {
        try {
            $partnerId = $this->request->get('partner_id');
            if (!$partnerId) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'partner_id is required'
                ], 400);
            }

            $odooDetail = \App\OdooDetail::firstOrNew(['partner_id' => $partnerId]);
            if ($odooDetail->status === 'success' || $odooDetail->status === 'Customer already exists') {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Customer is already created in Odoo.'
                ], 400);
            }

            $partner = PartnerData::with('parent')->find($partnerId);

            if (!$partner) {
                return response()->json([
                    'status' => 'error',
                    'message' => 'Partner not found'
                ], 404);
            }

            $payload = $this->mapPartnerToOdooPayload($partner);

            $odooService = new \App\Odoo\OdooService();
            $apiResult = $odooService->createCustomer($payload);

            if ($apiResult['http_code'] === 500 && isset($apiResult['message'])) {
                return response()->json([
                    'status' => 'error',
                    'message' => $apiResult['message'],
                    'error' => null
                ], 500);
            }

            $statusCode = $apiResult['http_code'];
            $responseData = is_array($apiResult['response']) ? $apiResult['response'] : json_decode($apiResult['response'], true);
            
            // Reassign $body for fallback error response later
            $body = is_string($apiResult['response']) ? $apiResult['response'] : json_encode($apiResult['response']);
            $odooDetail->api_response = $body;
            $odooDetail->created_by = Auth::user()->id ?? 107;

            if ($statusCode >= 200 && $statusCode < 300) {
                $odooDetail->status = 'success';
                if (isset($responseData['customer']['customer_id'])) {
                    $odooDetail->odoo_customer_id = $responseData['customer']['customer_id'];
                }
                $odooDetail->save();

                return response()->json([
                    'status' => 'success',
                    'message' => 'Successfully created customer in Odoo',
                    'data' => $responseData,
                ], $statusCode);
            } else {
                if (isset($responseData['message']) && $responseData['message'] === 'Customer already exists') {
                    $odooDetail->status = 'Customer already exists';
                } else {
                    $odooDetail->status = 'failed';
                }
                $odooDetail->save();

                $errorMsg = 'Failed to create customer in Odoo';
                if (is_array($responseData) && isset($responseData['message'])) {
                    $errorMsg = $responseData['message'];
                }

                return response()->json([
                    'status' => 'error',
                    'message' => $errorMsg,
                    'error' => $responseData ?? $body,
                ], $statusCode);
            }

        } catch (\Exception $e) {
            Log::error('Odoo createCustomer Exception: ' . $e->getMessage(), [
                'trace' => $e->getTraceAsString()
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'An internal error occurred',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    private function mapPartnerToOdooPayload(PartnerData $partner)
    {
        $payload = $this->buildPartnerData($partner);

        // Map parent if exists
        if ($partner->parent) {
            $payload['parent_company'] = $this->buildPartnerData($partner->parent);
        } else {
            $payload['parent_company'] = new \stdClass();
        }

        return $payload;
    }

    private function buildPartnerData(PartnerData $partner)
    {
        $uniqueCode = strtoupper(substr(trim($partner->name), 0, 3)) . '-' . $partner->id;

        return [
            "name"                => $partner->name ?? "",
            "phone"               => $partner->mobile ?? "",
            "email"               => $partner->email ?? "",
            "vat"                 => $partner->gstn ?? "",
            "pan"                 => $partner->pan ?? "",
            "tan"                 => $partner->tan ?? "",
            "gst_treatment"       => "regular",
            "company_name"        => $partner->company ?? "",
            "contact_type"        => "customer",
            "partner_unique_code" => $uniqueCode,
            "product"             => $partner->product ?? "",
            "source"              => $partner->source ?? "CreadFair", // Fallback to CreadFair if null
            "segment"             => $partner->industry ?? "Udhyam", // Mapped from industry, defaulting to Udhyam
            "address" => [
                "street"  => $partner->gst_address ?? "",
                "street2" => "",
                "city"    => $partner->city ?? "",
                "state"   => $partner->state ?? "",
                "country" => "India",
                "zip"     => $partner->zip ?? ""
            ]
        ];
    }

    public function getJvSteps($stepKey = '', $application = ''){

        $steps = [

            // ── 1. Disbursement ──────────────────────────────────────────────
            [
                'section' => 'Disbursement',
                'steps'   => [
                    [
                        'id'           => 'disbursement_pv',
                        'voucher_type' => 'Payment Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Loans A/c', 'debit' => '10,000,000.00', 'credit' => '-', 'gl_code' => 133001, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Bank A/c',  'debit' => '-', 'credit' => '10,000,000.00', 'gl_code' => 100201, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

            // ── 2. Interest ───────────────────────────────────────────────────
            [
                'section' => 'Interest',
                'steps'   => [
                    [
                        'id'           => 'interest_accrued_not_due_month_end_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Interest Accrued and not due', 'debit' => '20,000.00', 'credit' => '-', 'gl_code' => 145001, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Interest Income',               'debit' => '-',         'credit' => '20,000.00', 'gl_code' => 303004, 'sequence' => 2],
                        ],
                    ],
                    [
                        'id'           => 'reversal_interest_accrued_not_due_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Interest Income',               'debit' => '20,000.00', 'credit' => '-', 'gl_code' => 303004, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Interest Accrued and not due',  'debit' => '-',         'credit' => '20,000.00', 'gl_code' => 145001, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

            // ── 3. Penal Charges ─────────────────────────────────────────────
            [
                'section' => 'Penal Charges',
                'steps'   => [
                    [
                        'id'           => 'penal_charges_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Penal charges receivable', 'debit' => '30,000.00', 'credit' => '-', 'gl_code' => 1, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Penal charges',             'debit' => '-',         'credit' => '30,000.00', 'gl_code' => 303006, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

            // ── 4. Foreclosure Charges ───────────────────────────────────────
            [
                'section' => 'Foreclosure Charges',
                'steps'   => [
                    [
                        'id'           => 'foreclosure_charges_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Forclosure charges receivable', 'debit' => '20,000.00', 'gl_code' => 1, 'credit' => '-', 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Forclosure charges',             'debit' => '-',         'credit' => '16,949.00', 'gl_code' => 1, 'sequence' => 2],
                            ['type' => 'Cr', 'account' => 'IGST',                           'debit' => '-',         'credit' => '3,051.00', 'gl_code' => 115007, 'sequence' => 3],
                            ['type' => 'Cr', 'account' => 'CGST',                           'debit' => '-',         'credit' => '3,051.00', 'gl_code' => 115002, 'sequence' => 4],
                            ['type' => 'Cr', 'account' => 'SGST',                           'debit' => '-',         'credit' => '3,051.00', 'gl_code' => 115010, 'sequence' => 5],
                        ],
                    ],
                ],
            ],

            // ── 5. Collections ───────────────────────────────────────────────
            [
                'section' => 'Collections',
                'steps'   => [
                    [
                        'id'           => 'collections_rv',
                        'voucher_type' => 'Receipt Voucher',
                        'entries'      => [
                            ['type' => 'Cr', 'account' => 'Interest Accrual',                       'debit' => '-',          'credit' => '20,000.00', 'gl_code' => 145000, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Loans',                                  'debit' => '-',          'credit' => '50,000.00', 'gl_code' => 133001, 'sequence' => 2],
                            ['type' => 'Cr', 'account' => 'Penal charges receivable',               'debit' => '-',          'credit' => '30,000.00', 'gl_code' => 1, 'sequence' => 3],
                            ['type' => 'Cr', 'account' => 'Forclosure charges receivable',          'debit' => '-',          'credit' => '20,000.00', 'gl_code' => 1, 'sequence' => 4],
                            ['type' => 'Cr', 'account' => 'Excess / advance received from customers','debit' => '-',         'credit' => '20,000.00', 'gl_code' => 236004, 'sequence' => 5],
                            ['type' => 'Dr', 'account' => 'Bank A/c',                               'debit' => '1,40,000.00','credit' => '-', 'gl_code' => 100201, 'sequence' => 6],
                        ],
                    ],
                    [
                        'id'           => 'refund_of_excess_pv',
                        'voucher_type' => 'Payment Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Excess / advance received from customers', 'debit' => '20,000.00', 'credit' => '-', 'gl_code' => 236004, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Bank A/c',                                  'debit' => '-',         'credit' => '90,000.00', 'gl_code' => 100201, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

            // ── 6. NPA / Bad Debts ───────────────────────────────────────────
            [
                'section' => 'NPA / Bad Debts',
                'steps'   => [
                    [
                        'id'           => 'bad_debts_written_off_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Bad Debts Written-Off', 'debit' => '20,000.00', 'credit' => '-', 'gl_code' => 418012, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'Loans A/c',             'debit' => '-',         'credit' => '20,000.00', 'gl_code' => 133001, 'sequence' => 2],
                        ],
                    ],
                    [
                        'id'           => 'write_off_collections_rv',
                        'voucher_type' => 'Receipt Voucher',
                        'entries'      => [
                            ['type' => 'Cr', 'account' => 'Bad Debts Recovered', 'debit' => '-',         'credit' => '20,000.00', 'gl_code' => 309005, 'sequence' => 1],
                            ['type' => 'Dr', 'account' => 'Bank A/c',            'debit' => '20,000.00', 'credit' => '-', 'gl_code' => 100201, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

            // ── 7. Loan Processing Fee ───────────────────────────────────────
            [
                'section' => 'Loan Processing Fee',
                'steps'   => [
                    [
                        'id'           => 'loan_processing_fee_gst_invoice',
                        'voucher_type' => 'GST Invoice',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Loan Processing Fee',                         'debit' => '10,000.00', 'credit' => '-', 'gl_code' => 300007, 'sequence' => 1],
                            ['type' => 'Dr', 'account' => 'Documentation Charges',                       'debit' => '2,000.00',  'credit' => '-', 'gl_code' => 300002, 'sequence' => 2],
                            ['type' => 'Dr', 'account' => 'GST',                                         'debit' => '2,160.00',  'credit' => '-', 'gl_code' => 206003, 'sequence' => 3],
                            ['type' => 'Cr', 'account' => 'Loan Processing Fee Receivable / Party Name', 'debit' => '-',         'credit' => '14,160.00', 'gl_code' => 1, 'sequence' => 4],
                        ],
                    ],
                    [
                        'id'           => 'tds_on_lpf_jv',
                        'voucher_type' => 'Journal Voucher',
                        'entries'      => [
                            ['type' => 'Dr', 'account' => 'Loan Processing Fee Receivable / Party Name', 'debit' => '1,200.00', 'credit' => '-', 'gl_code' => 1, 'sequence' => 1],
                            ['type' => 'Cr', 'account' => 'TDS recoverable',                             'debit' => '-',        'credit' => '1,200.00', 'gl_code' => 160004, 'sequence' => 2],
                        ],
                    ],
                    [
                        'id'           => 'lpf_received_rv',
                        'voucher_type' => 'Receipt Voucher',
                        'entries'      => [
                            ['type' => 'Cr', 'account' => 'Loan Processing Fee Receivable / Party Name', 'debit' => '-',         'credit' => '12,960.00', 'gl_code' => 1, 'sequence' => 1],
                            ['type' => 'Dr', 'account' => 'Bank A/c',                                    'debit' => '12,960.00', 'credit' => '-', 'gl_code' => 100201, 'sequence' => 2],
                        ],
                    ],
                ],
            ],

        ];

        if ($stepKey) {
            foreach ($steps as $step) {
                foreach ($step['steps'] as $stepEntry) {
                    if ($stepEntry['id'] === $stepKey) {
                        return $stepEntry['entries'];
                    }
                }
            }

            return [];
        }

        return $steps;
    }
}
