<?php

namespace App\Services;

use App\Models\Zone;
use App\Models\ZoneRule;

class FeasibilityCalculatorService
{
    /**
     * Core feasibility calculation.
     *
     * @param  array{
     *   plot_area_sqm: float,
     *   zone: Zone,
     *   zone_rule: ZoneRule|null,
     *   road_width_m: float,
     *   restriction_flags: array,
     *   state_name?: string,
     *   project_type?: string,
     * } $input
     * @return array
     */
    public function calculate(array $input): array
    {
        $plotArea    = (float) $input['plot_area_sqm'];
        $zone        = $input['zone'];
        $rule        = $input['zone_rule'] ?? null;
        $roadWidth   = (float) ($input['road_width_m'] ?? 6.0);
        $flags       = $input['restriction_flags'] ?? [];
        $stateName   = $input['state_name'] ?? 'default';
        $projectType = $input['project_type'] ?? 'residential';
        $log         = [];

        // ── 1. Choose the FAR & parameters (rule takes priority over zone defaults) ──
        $maxFar            = $rule?->max_far            ?? $zone->far_fsi            ?? 1.5;
        $maxHeightM        = $rule?->max_height_m       ?? $zone->max_height_m       ?? 15.0;
        $coveragePct       = $rule?->max_ground_coverage ?? $zone->max_ground_coverage ?? 40.0;
        $openSpacePct      = $rule?->open_space_pct     ?? $zone->open_space_pct     ?? 10.0;
        $frontSetback      = $rule?->front_setback_m    ?? $zone->front_setback_m    ?? 3.0;
        $sideSetback       = $rule?->side_setback_m     ?? $zone->side_setback_m     ?? 1.5;
        $rearSetback       = $rule?->rear_setback_m     ?? $zone->rear_setback_m     ?? 3.0;
        $parkingRatio      = $rule?->parking_ratio_ecs  ?? 0.5;

        $log[] = "Using FAR = {$maxFar}, Coverage = {$coveragePct}%, Max Height = {$maxHeightM}m";

        // ── 2. Open space deduction ──
        $openSpaceSqm   = round($plotArea * ($openSpacePct / 100), 2);
        $netPlotArea    = $plotArea - $openSpaceSqm;
        $log[] = "Open space required: {$openSpaceSqm} sqm ({$openSpacePct}%). Net plot: {$netPlotArea} sqm";

        // ── 3. Ground coverage ──
        $groundCoverage = round($netPlotArea * ($coveragePct / 100), 2);
        $log[] = "Ground coverage allowed (on net): {$groundCoverage} sqm";

        // ── 4. Max buildable area from FAR ──
        // FAR is applied on gross plot area in most Indian regulations
        $maxBuildable = round($plotArea * $maxFar, 2);
        $log[] = "Max buildable area (FAR x gross): {$maxBuildable} sqm";

        // ── 5. Estimate floors ──
        $estimatedFloors = ($groundCoverage > 0) ? floor($maxBuildable / $groundCoverage) : 1;
        $log[] = "Estimated floors before height check: {$estimatedFloors}";

        // ── 6. Height constraint ──
        $avgFloorHeightM = 3.2;
        $heightAllowedFloors = ($avgFloorHeightM > 0) ? floor($maxHeightM / $avgFloorHeightM) : $estimatedFloors;

        if ($estimatedFloors > $heightAllowedFloors) {
            $estimatedFloors = $heightAllowedFloors;
            $maxBuildable = round($groundCoverage * $estimatedFloors, 2);
            $log[] = "Height restricted to {$maxHeightM}m → capped at {$estimatedFloors} floors, buildable area = {$maxBuildable} sqm";
        }

        // ── 7. Parking requirement ──
        $parkingRequired = (int) round($maxBuildable / 100 * $parkingRatio);
        $log[] = "Parking required: {$parkingRequired} ECS";

        // ── 8. Setback summary ──
        $setbacks = [
            'front_m' => $frontSetback,
            'side_m'  => $sideSetback,
            'rear_m'  => $rearSetback,
            'note'    => 'Setbacks are from plot boundary; verify with local authority.',
        ];

        // ── 9. Permitted uses ──
        $permittedUses = $this->getPermittedUses($zone->zone_type, $zone->permitted_uses);

        // ── 10. Feasibility score ──
        $score = $this->computeScore($maxFar, $plotArea, $maxBuildable, $flags);
        $log[] = "Feasibility score: {$score}/100";

        // ── 11. Restriction applicability ──
        $isFeasible = !($flags['crz'] ?? false) &&
                      !($flags['nhai_buffer'] ?? false);

        if (!$isFeasible) {
            $score = min($score, 20);
            $log[] = "Score capped at 20 due to active restriction flags.";
        }

        // ── 12. Cost & ROI estimation ──
        $costEstimates = $this->estimateCostAndRoi(
            $zone->zone_type,
            $stateName,
            $maxBuildable,
            $groundCoverage,
            $projectType
        );
        $log[] = sprintf(
            "Cost estimate: ₹%s – ₹%s | GDV: ₹%s | ROI: %s%%",
            number_format($costEstimates['construction_cost_min_inr']),
            number_format($costEstimates['construction_cost_max_inr']),
            number_format($costEstimates['gross_development_value_inr']),
            $costEstimates['roi_pct']
        );

        return [
            'feasible'               => $isFeasible,
            'feasibility_score'      => $score,
            'plot_area_sqm'          => $plotArea,
            'road_width_m'           => $roadWidth,
            'max_far'                => $maxFar,
            'max_height_m'           => $maxHeightM,
            'coverage_pct'           => $coveragePct,
            'open_space_sqm'         => $openSpaceSqm,
            'net_plot_area_sqm'      => $netPlotArea,
            'ground_coverage_sqm'    => $groundCoverage,
            'max_buildable_area_sqm' => $maxBuildable,
            'max_floors'             => (int) $estimatedFloors,
            'max_height_m_allowed'   => $maxHeightM,
            'parking_required_ecs'   => $parkingRequired,
            'front_setback_m'        => $frontSetback,
            'side_setback_m'         => $sideSetback,
            'rear_setback_m'         => $rearSetback,
            'setback_summary'        => $setbacks,
            'permitted_uses'         => $permittedUses,
            'restriction_flags'      => $flags,
            'rule_source'            => $rule?->rule_source ?? $zone->regulation_ref ?? 'Standard zone defaults',
            'zone_name'              => $zone->name,
            'zone_type'              => $zone->zone_type,
            'project_type'           => $projectType,
            'cost_estimates'         => $costEstimates,
            'calculation_log'        => $log,
        ];
    }

    /**
     * Estimate construction cost and ROI for the given zone/state/project type.
     */
    public function estimateCostAndRoi(
        string $zoneType,
        string $stateName,
        float  $buildableArea,
        float  $groundCoverage,
        string $projectType = 'residential'
    ): array {
        // Construction cost per sqm (INR) — min/max by state (avg contractor rates, 2025)
        $constructionRates = [
            'Maharashtra'      => ['min' => 2500, 'max' => 4500],
            'Karnataka'        => ['min' => 2200, 'max' => 4000],
            'Gujarat'          => ['min' => 2000, 'max' => 3800],
            'Delhi'            => ['min' => 3000, 'max' => 5500],
            'Tamil Nadu'       => ['min' => 2200, 'max' => 4000],
            'Telangana'        => ['min' => 2000, 'max' => 3800],
            'Andhra Pradesh'   => ['min' => 1900, 'max' => 3500],
            'Uttar Pradesh'    => ['min' => 1800, 'max' => 3200],
            'Rajasthan'        => ['min' => 1800, 'max' => 3200],
            'West Bengal'      => ['min' => 2000, 'max' => 3800],
            'Madhya Pradesh'   => ['min' => 1700, 'max' => 3000],
            'Haryana'          => ['min' => 2200, 'max' => 4000],
            'Punjab'           => ['min' => 2000, 'max' => 3700],
            'Bihar'            => ['min' => 1600, 'max' => 2800],
            'Odisha'           => ['min' => 1700, 'max' => 3000],
            'Kerala'           => ['min' => 2500, 'max' => 4500],
            'Goa'              => ['min' => 2800, 'max' => 5000],
        ];

        // Project type cost multiplier
        $typeMultiplier = match ($projectType) {
            'commercial' => 1.45,
            'industrial' => 1.10,
            'mixed'      => 1.30,
            default      => 1.00, // residential
        };

        $rates  = $constructionRates[$stateName] ?? ['min' => 2000, 'max' => 3800];
        $minPsm = $rates['min'] * $typeMultiplier;
        $maxPsm = $rates['max'] * $typeMultiplier;

        $constMin = (int) round($buildableArea * $minPsm);
        $constMax = (int) round($buildableArea * $maxPsm);

        // Sale / market value per sqm by zone type and state
        $saleRates = [
            'Maharashtra'  => ['Residential' => 9000,  'Commercial' => 14000, 'Industrial' => 5500, 'Mixed' => 11000, 'default' => 8500],
            'Karnataka'    => ['Residential' => 7500,  'Commercial' => 11000, 'Industrial' => 4800, 'Mixed' => 9000,  'default' => 7000],
            'Delhi'        => ['Residential' => 14000, 'Commercial' => 22000, 'Industrial' => 9000, 'Mixed' => 16000, 'default' => 12000],
            'Gujarat'      => ['Residential' => 5500,  'Commercial' => 9000,  'Industrial' => 4200, 'Mixed' => 7000,  'default' => 5500],
            'Telangana'    => ['Residential' => 6500,  'Commercial' => 10000, 'Industrial' => 4500, 'Mixed' => 8000,  'default' => 6000],
            'Tamil Nadu'   => ['Residential' => 6000,  'Commercial' => 9500,  'Industrial' => 4500, 'Mixed' => 7500,  'default' => 5800],
            'Haryana'      => ['Residential' => 7000,  'Commercial' => 11000, 'Industrial' => 5000, 'Mixed' => 9000,  'default' => 6500],
            'Kerala'       => ['Residential' => 6500,  'Commercial' => 9500,  'Industrial' => 4200, 'Mixed' => 8000,  'default' => 6000],
            'Goa'          => ['Residential' => 9000,  'Commercial' => 13000, 'Industrial' => 5500, 'Mixed' => 11000, 'default' => 8500],
        ];

        $stateRates = $saleRates[$stateName] ?? ['Residential' => 5500, 'Commercial' => 9000, 'Industrial' => 4000, 'Mixed' => 7000, 'default' => 5200];
        $salePsm    = $stateRates[$zoneType] ?? $stateRates['default'];
        $gdv        = (int) round($buildableArea * $salePsm);

        $avgCost    = ($constMin + $constMax) / 2;
        $profit     = $gdv - $avgCost;
        $roiPct     = $avgCost > 0 ? round(($profit / $avgCost) * 100, 1) : 0;

        // Rental yield estimate
        $rentalYield = match ($zoneType) {
            'Commercial' => 0.065,
            'Industrial' => 0.050,
            'Mixed'      => 0.040,
            default      => 0.030,
        };
        $annualRent  = (int) round($gdv * $rentalYield);
        $monthlyRent = (int) round($annualRent / 12);
        $breakevenYears = ($annualRent > 0) ? round($avgCost / $annualRent, 1) : null;

        return [
            'construction_cost_min_inr'   => $constMin,
            'construction_cost_max_inr'   => $constMax,
            'construction_rate_min_sqm'   => (int) $rates['min'],
            'construction_rate_max_sqm'   => (int) $rates['max'],
            'gross_development_value_inr' => $gdv,
            'sale_rate_per_sqm_inr'       => $salePsm,
            'estimated_profit_inr'        => (int) $profit,
            'roi_pct'                     => $roiPct,
            'monthly_rent_estimate_inr'   => $monthlyRent,
            'annual_rent_estimate_inr'    => $annualRent,
            'breakeven_years'             => $breakevenYears,
            'note'                        => 'Indicative estimates based on prevailing market rates. Consult a valuer for precise figures.',
        ];
    }

    private function computeScore(float $far, float $plotArea, float $buildable, array $flags): int
    {
        $score = 50;

        // Higher FAR = better development potential
        if ($far >= 3.0)      $score += 20;
        elseif ($far >= 2.0)  $score += 15;
        elseif ($far >= 1.5)  $score += 10;
        elseif ($far >= 1.0)  $score += 5;

        // Larger plot = more flexibility
        if ($plotArea >= 5000)      $score += 15;
        elseif ($plotArea >= 2000)  $score += 10;
        elseif ($plotArea >= 1000)  $score += 5;

        // Decent buildable area
        if ($buildable >= 10000)    $score += 10;
        elseif ($buildable >= 3000) $score += 5;

        // Deductions for restrictions
        if ($flags['crz'] ?? false)           $score -= 40;
        if ($flags['flood_zone'] ?? false)    $score -= 25;
        if ($flags['nhai_buffer'] ?? false)   $score -= 35;
        if ($flags['eco_sensitive'] ?? false) $score -= 30;
        if ($flags['heritage_zone'] ?? false) $score -= 20;
        if ($flags['airport_funnel'] ?? false) $score -= 15;

        return max(0, min(100, $score));
    }

    private function getPermittedUses(string $zoneType, ?string $zonePermitted): array
    {
        $defaults = match ($zoneType) {
            'Residential' => ['Residential (Dwelling Houses)', 'Affordable Housing', 'Schools (Primary)', 'Places of Worship', 'Retail (Ground Floor Only)'],
            'Commercial'  => ['Commercial Offices', 'Retail / Shopping', 'Hotels', 'Restaurants', 'Banks', 'Showrooms'],
            'Industrial'  => ['Light Industry', 'Warehousing', 'Service Industries', 'Industrial Estates'],
            'Mixed'       => ['Residential', 'Commercial Offices', 'Retail', 'Hotels', 'Mixed Use Towers'],
            'Agricultural'=> ['Agriculture', 'Horticulture', 'Farm Houses (limited)', 'Agricultural Processing'],
            'Green Belt'  => ['Parks', 'Green Spaces', 'Recreational Open Areas'],
            'Heritage'    => ['Restoration / Conservation Only', 'Cultural Uses', 'Tourism (Limited)'],
            default       => ['As per applicable regulations'],
        };

        if ($zonePermitted) {
            $extra = array_filter(array_map('trim', explode(',', $zonePermitted)));
            return array_unique(array_merge($extra, $defaults));
        }

        return $defaults;
    }
}
