<?php

namespace App\Services;

use App\Models\PlotSurvey;
use Illuminate\Support\Facades\Storage;

/**
 * AI-powered Plot/PT Survey Analyzer using GPT-4o Vision.
 *
 * What it does:
 *   1. Accepts uploaded survey image (JPG/PNG/TIFF) or PDF map
 *   2. Sends to GPT-4o Vision with a specialized prompt
 *   3. Extracts: plot area, dimensions, road frontage, survey number, land use, shape points
 *   4. Optionally queries Bhulekh API (Maharashtra land records) for authoritative data
 *   5. Returns structured PlotSurvey model with extracted data
 *
 * Supported inputs:
 *   - 7/12 extract (Satbara Utara) — Maharashtra
 *   - Property Card (Mumbai)
 *   - PT Survey / CTS map
 *   - Sketch map / site plan image
 *   - Cadastral map screenshot
 */
class PlotSurveyAnalyzerService
{
    private const SURVEY_VISION_PROMPT = <<<'PROMPT'
You are an expert in Indian cadastral surveys, land records, and property title documents.
Analyze the provided document/image and extract ALL available information about the plot/land parcel.

Extract the following and return as JSON:
{
  "survey_number": "CTS No. / Survey No. / Gut No. / Khasra No.",
  "village_name": "...",
  "taluka_name": "...",
  "district_name": "...",
  "state_name": "...",
  "owner_name": "...",
  "ownership_type": "private|government|trust|cooperative|unknown",
  "land_use_type": "residential|agricultural|commercial|industrial|mixed|unknown",
  "area_sqm": null,
  "area_sqyd": null,
  "area_sqft": null,
  "area_hectare": null,
  "area_acre": null,
  "area_guntha": null,
  "plot_length_m": null,
  "plot_width_m": null,
  "road_frontage_m": null,
  "road_width_m": null,
  "north_boundary": "...",
  "south_boundary": "...",
  "east_boundary": "...",
  "west_boundary": "...",
  "dimensions_detected": [
    {"side": "north|south|east|west|irregular", "length_m": null, "annotation": "..."}
  ],
  "shape": "rectangular|square|triangular|l-shaped|irregular",
  "plot_shape_points": null,
  "document_type": "7/12|Property Card|PT Survey|Site Plan|Cadastral Map|Other",
  "mutation_number": null,
  "subdivision_number": null,
  "encumbrances": "...",
  "special_remarks": "...",
  "confidence": 0.0
}

RULES:
- Use null for any field not found in the document.
- Convert all areas to sq metres if possible (1 guntha = 101.17 sqm, 1 acre = 4046.86 sqm).
- confidence: 0.0-1.0 reflecting certainty of key measurements.
- For scanned/blurry documents, OCR all visible text first, then extract fields.
- Return ONLY the JSON object, no additional text.
PROMPT;

    public function __construct(
        private readonly OpenAIService $ai,
    ) {}

    // ── Main entry point ──────────────────────────────────────────────────────

    /**
     * Analyze an uploaded survey document and populate the PlotSurvey model.
     */
    public function analyze(PlotSurvey $survey): void
    {
        if (! OpenAIService::isEnabled()) {
            $survey->update([
                'ai_status' => 'failed',
                'ai_error'  => 'AI features are disabled. Please configure your OpenAI API key in Admin → Settings → AI Settings.',
            ]);
            return;
        }

        $survey->update(['ai_status' => 'processing']);

        try {
            $filePath = Storage::disk('local')->path($survey->survey_file_path);
            $fileType = $survey->survey_file_type;

            // Read and base64-encode the file
            $fileBytes = file_get_contents($filePath);
            if ($fileBytes === false) {
                throw new \RuntimeException("Cannot read survey file: {$filePath}");
            }

            $base64  = base64_encode($fileBytes);
            $mime    = $this->mimeType($fileType);
            $result  = $this->ai->visionAnalyzeJson($base64, $mime, self::SURVEY_VISION_PROMPT);

            // Convert area units to sqm as canonical
            $areaSqm = $this->resolveAreaSqm($result);

            // Fetch Bhulekh data if survey number available
            $bhulekh = null;
            if (! empty($result['survey_number']) && config('services.bhulekh.enabled')) {
                $bhulekh = $this->fetchBhulekh($result['survey_number'], $result['state_name'] ?? '');
            }

            $survey->update([
                'ai_status'            => 'completed',
                'ai_error'             => null,
                'extracted_area_sqm'   => $areaSqm,
                'extracted_area_sqyd'  => $areaSqm ? round($areaSqm / 0.8361, 2) : null,
                'road_frontage_m'      => $result['road_frontage_m'] ?? null,
                'plot_length_m'        => $result['plot_length_m'] ?? null,
                'plot_width_m'         => $result['plot_width_m'] ?? null,
                'survey_number'        => $result['survey_number'] ?? null,
                'village_name'         => $result['village_name'] ?? null,
                'taluka_name'          => $result['taluka_name'] ?? null,
                'district_name'        => $result['district_name'] ?? null,
                'land_use_type'        => $result['land_use_type'] ?? null,
                'ownership_type'       => $result['ownership_type'] ?? null,
                'plot_shape_points'    => $result['plot_shape_points'] ?? null,
                'ai_analysis_raw'      => $result,
                'dimensions_detected'  => $result['dimensions_detected'] ?? null,
                'bhulekh_data'         => $bhulekh,
                'bhulekh_fetched_at'   => $bhulekh ? now() : null,
            ]);

        } catch (\Throwable $e) {
            $survey->update([
                'ai_status' => 'failed',
                'ai_error'  => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    // ── Area resolution ───────────────────────────────────────────────────────

    /**
     * Find best area value and normalise to sq metres.
     */
    private function resolveAreaSqm(array $result): ?float
    {
        if (! empty($result['area_sqm'])) {
            return (float) $result['area_sqm'];
        }
        if (! empty($result['area_sqyd'])) {
            return round((float) $result['area_sqyd'] * 0.8361, 4);
        }
        if (! empty($result['area_sqft'])) {
            return round((float) $result['area_sqft'] * 0.0929, 4);
        }
        if (! empty($result['area_guntha'])) {
            return round((float) $result['area_guntha'] * 101.17, 4);
        }
        if (! empty($result['area_acre'])) {
            return round((float) $result['area_acre'] * 4046.86, 4);
        }
        if (! empty($result['area_hectare'])) {
            return round((float) $result['area_hectare'] * 10000, 4);
        }
        // Compute from dimensions if available
        if (! empty($result['plot_length_m']) && ! empty($result['plot_width_m'])) {
            return round((float) $result['plot_length_m'] * (float) $result['plot_width_m'], 4);
        }
        return null;
    }

    // ── Bhulekh integration ───────────────────────────────────────────────────

    /**
     * Attempt to fetch land record data from Bhulekh APIs.
     * Currently supports Maharashtra (Mahabhulekh).
     * Returns null if disabled or data unavailable.
     */
    private function fetchBhulekh(string $surveyNo, string $stateName): ?array
    {
        // Bhulekh APIs are not publicly documented REST APIs;
        // most states use form-based web portals.
        // This is a placeholder for when a licensed / scraping integration is available.
        // For now, return metadata indicating the lookup was attempted.
        return [
            'attempted'   => true,
            'survey_no'   => $surveyNo,
            'state'       => $stateName,
            'status'      => 'manual_lookup_required',
            'portal_url'  => $this->getBhulekhPortalUrl($stateName),
            'note'        => 'Automated Bhulekh lookup requires licensed API access. Please verify manually.',
        ];
    }

    private function getBhulekhPortalUrl(string $stateName): string
    {
        $portals = [
            'maharashtra' => 'https://bhulekh.mahabhumi.gov.in',
            'gujarat'     => 'https://anyror.gujarat.gov.in',
            'karnataka'   => 'https://landrecords.karnataka.gov.in',
            'tamilnadu'   => 'https://eservices.tn.gov.in/eservicesnew/index.html',
            'andhra'      => 'https://meebhoomi.ap.gov.in',
            'telangana'   => 'https://dharani.telangana.gov.in',
            'up'          => 'https://upbhulekh.gov.in',
            'rajasthan'   => 'https://apnakhata.rajasthan.gov.in',
            'madhya'      => 'https://mpbhulekh.gov.in',
            'haryana'     => 'https://jamabandi.nic.in',
        ];

        $key = strtolower($stateName);
        foreach ($portals as $k => $url) {
            if (str_contains($key, $k)) {
                return $url;
            }
        }
        return 'https://dilrmp.gov.in'; // DILRMP national portal
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    private function mimeType(string $fileType): string
    {
        return match (strtolower($fileType)) {
            'jpg', 'jpeg' => 'image/jpeg',
            'png'         => 'image/png',
            'tiff', 'tif' => 'image/tiff',
            'pdf'         => 'application/pdf',
            default       => 'image/jpeg',
        };
    }

    /**
     * Re-analyze a survey with additional user context hints.
     */
    public function reanalyzeWithHints(PlotSurvey $survey, string $userHints): void
    {
        $filePath  = Storage::disk('local')->path($survey->survey_file_path);
        $base64    = base64_encode(file_get_contents($filePath));
        $mime      = $this->mimeType($survey->survey_file_type ?? 'jpg');
        $prompt    = self::SURVEY_VISION_PROMPT
            . "\n\nUser provided additional context: {$userHints}\nUse this context to improve extraction accuracy.";

        $result   = $this->ai->visionAnalyzeJson($base64, $mime, $prompt);
        $areaSqm  = $this->resolveAreaSqm($result);

        $survey->update([
            'ai_analysis_raw'    => $result,
            'extracted_area_sqm' => $areaSqm ?? $survey->extracted_area_sqm,
            'dimensions_detected'=> $result['dimensions_detected'] ?? $survey->dimensions_detected,
        ]);
    }
}
