# -*- coding: utf-8 -*-
import os
import time
import tempfile
import urllib.request
import urllib.parse
import ssl
from qgis.core import (
    QgsProcessingAlgorithm,
    QgsProcessingParameterFeatureSource,
    QgsProcessingParameterField,
    QgsProcessingParameterString,
    QgsProcessingParameterFolderDestination,
    QgsProcessingParameterEnum,
    QgsProcessingException
)
from .license_guard import SupabaseGuard


class DownloadRBIToolPro(QgsProcessingAlgorithm):
    # Constants
    DOWNLOAD_LEVEL = 'DOWNLOAD_LEVEL'
    ADMIN_LAYER = 'ADMIN_LAYER'
    FIELD_KAB = 'FIELD_KAB'
    FIELD_PROV = 'FIELD_PROV'
    KABUPATEN = 'KABUPATEN'
    PROVINSI = 'PROVINSI'
    TOKEN = 'TOKEN'  # nosec B105
    SKALA = 'SKALA'
    OUTPUT_FOLDER = 'OUTPUT_FOLDER'

    def initAlgorithm(self, config=None):
        self.addParameter(QgsProcessingParameterEnum(
            self.DOWNLOAD_LEVEL,
            'Tingkat Download',
            options=['Kabupaten/Kota', 'Provinsi'],
            defaultValue=0,
            allowMultiple=False
        ))

        self.addParameter(QgsProcessingParameterFeatureSource(
            self.ADMIN_LAYER, 'Layer Administrasi', [2]  # Polygon
        ))

        self.addParameter(QgsProcessingParameterField(
            self.FIELD_KAB,
            'Field Kabupaten',
            parentLayerParameterName=self.ADMIN_LAYER,
            type=QgsProcessingParameterField.DataType.String
        ))

        self.addParameter(QgsProcessingParameterField(
            self.FIELD_PROV,
            'Field Provinsi',
            parentLayerParameterName=self.ADMIN_LAYER,
            type=QgsProcessingParameterField.DataType.String
        ))

        self.addParameter(QgsProcessingParameterString(
            self.KABUPATEN, 'Nama Kabupaten/Kota (Manual Input)', optional=True
        ))

        self.addParameter(QgsProcessingParameterString(
            self.PROVINSI, 'Nama Provinsi (Manual Input)', optional=True
        ))

        self.addParameter(QgsProcessingParameterString(
            self.TOKEN, 'API Token'
        ))

        self.addParameter(QgsProcessingParameterEnum(
            self.SKALA,
            'Skala Peta',
            options=['25K', '50K'],
            defaultValue=0,
            allowMultiple=False
        ))

        self.addParameter(QgsProcessingParameterFolderDestination(
            self.OUTPUT_FOLDER, 'Output Folder'
        ))

    def processAlgorithm(self, parameters, context, feedback):
        # 1. License Check
        feedback.pushInfo("[1/4] Memeriksa lisensi...")
        is_valid, msg, info = SupabaseGuard.check_license(
            "BIG Downloader QGIS", "free"
        )
        feedback.pushInfo(msg)
        if not is_valid:
            raise QgsProcessingException("Gagal memvalidasi lisensi.")

        # 2. Get Params
        download_level = self.parameterAsEnum(parameters, self.DOWNLOAD_LEVEL, context)
        layer = self.parameterAsSource(parameters, self.ADMIN_LAYER, context)
        field_kab = self.parameterAsString(parameters, self.FIELD_KAB, context)
        field_prov = self.parameterAsString(parameters, self.FIELD_PROV, context)
        kab_input = self.parameterAsString(parameters, self.KABUPATEN, context)
        prov_input = self.parameterAsString(parameters, self.PROVINSI, context)
        token = self.parameterAsString(parameters, self.TOKEN, context)

        skala_idx = self.parameterAsEnum(parameters, self.SKALA, context)
        skala_opts = ['25K', '50K']
        skala = skala_opts[skala_idx]

        output_folder = self.parameterAsString(
            parameters, self.OUTPUT_FOLDER, context
        )

        # Handle Temporary Output
        if output_folder == 'TEMPORARY_OUTPUT':
            output_folder = os.path.join(tempfile.gettempdir(), 'BIG_RBI_Output')
            if not os.path.exists(output_folder):
                os.makedirs(output_folder)
            feedback.pushInfo(
                f"Info: Menggunakan folder sementara: {output_folder}"
            )

        # Check if there is an active selection in the map layer
        has_selection = False
        layer_obj = self.parameterAsVectorLayer(parameters, self.ADMIN_LAYER, context)
        if layer_obj is not None:
            has_selection = (layer_obj.selectedFeatureCount() > 0)

        # 3. Determine target list of (kabupaten, provinsi) tuples
        targets = []

        if download_level == 0:  # Kabupaten/Kota
            final_kab = ""
            final_prov = ""

            feature_count = layer.featureCount()
            if has_selection and feature_count > 0:
                iterator = layer.getFeatures()
                feat = next(iterator, None)
                if feat:
                    final_kab = str(feat[field_kab])
                    final_prov = str(feat[field_prov])
                    feedback.pushInfo(
                        f"Info: Menggunakan fitur terpilih ({feature_count}): "
                        f"{final_kab}, {final_prov}"
                    )
                if feature_count > 1:
                    feedback.pushInfo(
                        f"Warning: {feature_count} fitur terpilih. Menggunakan yang pertama."
                    )
            else:
                if kab_input:
                    feedback.pushInfo(f"[2/4] Mencari lokasi kabupaten {kab_input}...")
                    found = False
                    for feat in layer.getFeatures():
                        k = str(feat[field_kab])
                        p = str(feat[field_prov])
                        if k.strip().lower() == kab_input.strip().lower():
                            final_kab = k
                            final_prov = p
                            found = True
                            break
                    if not found:
                        raise QgsProcessingException(
                            f"Kabupaten {kab_input} tidak ditemukan di layer."
                        )
                else:
                    raise QgsProcessingException(
                        "Harap pilih fitur di peta atau masukkan Nama Kabupaten secara manual."
                    )
            
            if final_kab and final_prov:
                targets.append((final_kab, final_prov))

        else:  # Provinsi
            final_prov = ""
            feature_count = layer.featureCount()
            if has_selection and feature_count > 0:
                iterator = layer.getFeatures()
                feat = next(iterator, None)
                if feat:
                    final_prov = str(feat[field_prov])
                    feedback.pushInfo(f"Info: Menggunakan provinsi dari fitur terpilih: {final_prov}")
            elif prov_input:
                final_prov = prov_input.strip()
                feedback.pushInfo(f"Info: Menggunakan nama provinsi manual: {final_prov}")
            elif kab_input:
                feedback.pushInfo(f"[2/4] Mencari provinsi untuk kabupaten {kab_input}...")
                for feat in layer.getFeatures():
                    k = str(feat[field_kab])
                    p = str(feat[field_prov])
                    if k.strip().lower() == kab_input.strip().lower():
                        final_prov = p
                        break
                if not final_prov:
                    raise QgsProcessingException(
                        f"Kabupaten {kab_input} tidak ditemukan untuk mencari provinsi."
                    )
            else:
                raise QgsProcessingException(
                    "Harap pilih fitur di peta, masukkan Nama Provinsi secara manual, atau masukkan Nama Kabupaten untuk mendeteksi provinsi."
                )

            # Find all unique kabupatens in final_prov
            kab_set = set()
            for feat in layer.getFeatures():
                p = str(feat[field_prov])
                if p.strip().lower() == final_prov.strip().lower():
                    k = str(feat[field_kab])
                    if k:
                        kab_set.add(k)

            if not kab_set:
                raise QgsProcessingException(
                    f"Tidak ada kabupaten/kota ditemukan untuk provinsi: {final_prov}"
                )

            sorted_kabs = sorted(list(kab_set))
            feedback.pushInfo(f"Info: Ditemukan {len(sorted_kabs)} kabupaten/kota di provinsi {final_prov}.")
            for k in sorted_kabs:
                targets.append((k, final_prov))

        # 4. Download
        ctx = ssl.create_default_context()
        ctx.check_hostname = False
        ctx.verify_mode = ssl.CERT_NONE

        if not os.path.exists(output_folder):
            try:
                os.makedirs(output_folder, exist_ok=True)
            except Exception: pass  # nosec

        feedback.pushInfo("\n=== MENGUNDUH DATA ===")
        success_count = 0

        for idx, (kab_name, prov_name) in enumerate(targets):
            if feedback.isCanceled():
                break

            feedback.pushInfo(f"\n[{idx + 1}/{len(targets)}] Mengunduh: {kab_name} ({prov_name})")

            url = (
                "https://tanahair.indonesia.go.id/api-inageo/unduh/rbi?"
                f"token={token}&"
                f"prov={urllib.parse.quote(prov_name)}&"
                f"kab={urllib.parse.quote(kab_name)}&"
                f"skala={skala}"
            )

            timestamp = time.strftime("%Y%m%d_%H%M%S")
            safe_kab = kab_name.replace(' ', '_')
            if not safe_kab:
                safe_kab = "UNKNOWN"
            filename = f"RBI_{safe_kab}_{skala}_{timestamp}.zip"
            output_path = os.path.join(output_folder, filename)

            try:
                req = urllib.request.Request(
                    url, headers={'User-Agent': 'Mozilla/5.0'}
                )
                with urllib.request.urlopen(req, context=ctx, timeout=300) as response:  # nosec B310
                    total_size = int(response.info().get('Content-Length') or 0)
                    downloaded = 0
                    chunk_size = 8192

                    with open(output_path, 'wb') as f:
                        while True:
                            if feedback.isCanceled():
                                break
                            chunk = response.read(chunk_size)
                            if not chunk:
                                break
                            f.write(chunk)
                            downloaded += len(chunk)
                            if total_size > 0:
                                feedback.setProgress(
                                    int((downloaded / total_size) * 100)
                                )

                feedback.pushInfo(f"Selesai! Output tersimpan di: {output_path}")
                success_count += 1
            except Exception as e:
                feedback.reportError(f"Gagal mengunduh {kab_name}: {str(e)}")

        feedback.pushInfo(f"\n=== SELESAI ===")
        feedback.pushInfo(f"Total berhasil diunduh: {success_count} dari {len(targets)}")

        return {self.OUTPUT_FOLDER: output_folder}

    def name(self):
        return 'download_rbi_tool_pro'

    def displayName(self):
        return '3. Download RBI'

    def group(self):
        return 'BIG Downloader Tools'

    def groupId(self):
        return 'big_downloader_v2'

    def shortHelpString(self):
        return (
            "Download data Vektor RBI (Rupa Bumi Indonesia) per wilayah administrasi.\n\n"
            "Data RBI bisa diunduh berdasarkan tingkat wilayah:\n"
            "- Provinsi\n"
            "- Kabupaten/Kota\n"
            "Mendukung berbagai skala (10K, 25K, 50K, 250K) sesuai ketersediaan."
        )

    def icon(self):
        import os
        from qgis.PyQt.QtGui import QIcon
        icon_path = os.path.join(os.path.dirname(__file__), '..', 'images', 'icon_rbi.png')
        return QIcon(icon_path)

    def createInstance(self):
        return DownloadRBIToolPro()
