# -*- coding: utf-8 -*-
"""Wildlife Sound Locator Dialog. Author: Lộc Vũ Trung"""
import datetime
from qgis.PyQt.QtGui import QFont
from qgis.PyQt.QtWidgets import (
    QDialog, QVBoxLayout, QHBoxLayout, QTabWidget,
    QWidget, QLabel, QPushButton, QGroupBox,
    QGridLayout, QDoubleSpinBox, QSpinBox, QComboBox,
    QLineEdit, QTextEdit, QDateTimeEdit, QTableWidget,
    QTableWidgetItem, QHeaderView, QFileDialog, QMessageBox,
    QAbstractItemView
)
from qgis.core import (
    QgsProject, QgsVectorLayer, QgsFeature, QgsGeometry,
    QgsPointXY, QgsField, QgsFields, QgsCoordinateReferenceSystem
)
from qgis.PyQt.QtCore import QVariant

from .species_data import (
    GROUPS, HABITATS, TERRAINS, WEATHER_CONDITIONS,
    WIND_DIRECTIONS, COUNT_OPTIONS, get_vn_names_by_group, lookup_species
)
from .engine import (
    destination_point, bearing_line_coords,
    confidence_sector_coords, triangulate, sector_area_ha
)
from .template import export_template, import_template


class WildlifeSoundDialog(QDialog):
    def __init__(self, iface, lang='vi', parent=None):
        super().__init__(parent)
        self.iface = iface
        self.lang = lang
        self.records = []
        self._setup_ui()

    def _setup_ui(self):
        self.setWindowTitle('Wildlife Sound Locator — LVT4U')
        self.setMinimumSize(900, 650)
        ly = QVBoxLayout(self)

        # Header
        hdr = QLabel('🔊 Wildlife Sound Locator')
        hdr.setFont(QFont('Segoe UI', 14, QFont.Bold))
        hdr.setStyleSheet('color:#1B5E20; padding:8px;')
        ly.addWidget(hdr)

        self.tabs = QTabWidget()
        ly.addWidget(self.tabs)

        self.tabs.addTab(self._tab_entry(), '📝 Nhập liệu / Data Entry')
        self.tabs.addTab(self._tab_results(), '🗺️ Kết quả / Results')
        self.tabs.addTab(self._tab_guide(), 'ℹ️ Hướng dẫn / Guide')

    # ── TAB 1: DATA ENTRY ──
    def _tab_entry(self):
        w = QWidget()
        ly = QVBoxLayout(w)

        # Form area
        form_box = QGroupBox('Thông tin quan sát / Observation Data')
        form = QGridLayout(form_box)

        r = 0
        # Position
        form.addWidget(QLabel('Kinh độ / Longitude:'), r, 0)
        self.spn_lon = QDoubleSpinBox()
        self.spn_lon.setRange(-180, 180)
        self.spn_lon.setDecimals(6)
        form.addWidget(self.spn_lon, r, 1)

        form.addWidget(QLabel('Vĩ độ / Latitude:'), r, 2)
        self.spn_lat = QDoubleSpinBox()
        self.spn_lat.setRange(-90, 90)
        self.spn_lat.setDecimals(6)
        form.addWidget(self.spn_lat, r, 3)

        r += 1
        form.addWidget(QLabel('Góc phương vị / Bearing (°):'), r, 0)
        self.spn_bearing = QSpinBox()
        self.spn_bearing.setRange(0, 360)
        form.addWidget(self.spn_bearing, r, 1)

        form.addWidget(QLabel('Cự ly / Distance (m):'), r, 2)
        self.spn_dist = QSpinBox()
        self.spn_dist.setRange(1, 5000)
        self.spn_dist.setValue(200)
        form.addWidget(self.spn_dist, r, 3)

        r += 1
        form.addWidget(QLabel('Sai số góc / Angle err (±°):'), r, 0)
        self.spn_aerr = QSpinBox()
        self.spn_aerr.setRange(1, 45)
        self.spn_aerr.setValue(15)
        form.addWidget(self.spn_aerr, r, 1)

        form.addWidget(QLabel('Sai số cự ly / Dist err (%):'), r, 2)
        self.spn_derr = QSpinBox()
        self.spn_derr.setRange(5, 80)
        self.spn_derr.setValue(30)
        form.addWidget(self.spn_derr, r, 3)

        r += 1
        form.addWidget(QLabel('Độ cao / Elevation (m):'), r, 0)
        self.spn_elev = QSpinBox()
        self.spn_elev.setRange(0, 9000)
        form.addWidget(self.spn_elev, r, 1)

        form.addWidget(QLabel('Hiện trạng / Habitat:'), r, 2)
        self.cmb_habitat = QComboBox()
        self.cmb_habitat.addItems(HABITATS)
        form.addWidget(self.cmb_habitat, r, 3)

        r += 1
        form.addWidget(QLabel('Địa hình / Terrain:'), r, 0)
        self.cmb_terrain = QComboBox()
        self.cmb_terrain.addItems(TERRAINS)
        form.addWidget(self.cmb_terrain, r, 1)

        form.addWidget(QLabel('Nhóm loài / Group:'), r, 2)
        self.cmb_group = QComboBox()
        self.cmb_group.addItems(GROUPS)
        self.cmb_group.currentTextChanged.connect(self._on_group_changed)
        form.addWidget(self.cmb_group, r, 3)

        r += 1
        form.addWidget(QLabel('Tên loài / Species:'), r, 0)
        self.cmb_species = QComboBox()
        self.cmb_species.setEditable(True)
        self._on_group_changed(self.cmb_group.currentText())
        self.cmb_species.currentTextChanged.connect(self._on_species_changed)
        form.addWidget(self.cmb_species, r, 1)

        form.addWidget(QLabel('Tên khoa học / Sci:'), r, 2)
        self.lbl_sci = QLabel('—')
        self.lbl_sci.setStyleSheet('font-style:italic; color:#555;')
        form.addWidget(self.lbl_sci, r, 3)

        r += 1
        form.addWidget(QLabel('Số lượng / Count:'), r, 0)
        self.cmb_count = QComboBox()
        self.cmb_count.addItems(COUNT_OPTIONS)
        form.addWidget(self.cmb_count, r, 1)

        form.addWidget(QLabel('Ngày giờ / Datetime:'), r, 2)
        self.dt_time = QDateTimeEdit()
        self.dt_time.setDateTime(datetime.datetime.now())
        self.dt_time.setCalendarPopup(True)
        form.addWidget(self.dt_time, r, 3)

        r += 1
        form.addWidget(QLabel('Người KS / Surveyor:'), r, 0)
        self.txt_surveyor = QLineEdit()
        form.addWidget(self.txt_surveyor, r, 1)

        form.addWidget(QLabel('Tuyến TT / Patrol:'), r, 2)
        self.txt_patrol = QLineEdit()
        form.addWidget(self.txt_patrol, r, 3)

        r += 1
        form.addWidget(QLabel('Thời tiết / Weather:'), r, 0)
        self.cmb_weather = QComboBox()
        self.cmb_weather.addItems(WEATHER_CONDITIONS)
        form.addWidget(self.cmb_weather, r, 1)

        form.addWidget(QLabel('Hướng gió / Wind:'), r, 2)
        self.cmb_wind = QComboBox()
        self.cmb_wind.addItems(WIND_DIRECTIONS)
        form.addWidget(self.cmb_wind, r, 3)

        r += 1
        form.addWidget(QLabel('Ghi chú / Notes:'), r, 0)
        self.txt_notes = QLineEdit()
        form.addWidget(self.txt_notes, r, 1, 1, 3)

        ly.addWidget(form_box)

        # Buttons
        btn_ly = QHBoxLayout()
        self.btn_add = QPushButton('✅ Thêm / Add')
        self.btn_add.setStyleSheet('background:#4CAF50;color:white;padding:6px 16px;border-radius:4px;font-weight:bold;')
        self.btn_add.clicked.connect(self._add_record)
        btn_ly.addWidget(self.btn_add)

        self.btn_del = QPushButton('🗑️ Xoá / Delete')
        self.btn_del.setStyleSheet('background:#f44336;color:white;padding:6px 16px;border-radius:4px;')
        self.btn_del.clicked.connect(self._del_record)
        btn_ly.addWidget(self.btn_del)

        btn_ly.addStretch()

        self.btn_tpl_export = QPushButton('📋 Xuất Template / Export')
        self.btn_tpl_export.clicked.connect(self._export_template)
        btn_ly.addWidget(self.btn_tpl_export)

        self.btn_tpl_import = QPushButton('📥 Nhập Excel / Import')
        self.btn_tpl_import.clicked.connect(self._import_template)
        btn_ly.addWidget(self.btn_tpl_import)

        ly.addLayout(btn_ly)

        # Data table
        self.tbl_data = QTableWidget(0, 8)
        self.tbl_data.setHorizontalHeaderLabels([
            'Lon', 'Lat', 'Bearing°', 'Dist(m)',
            'Loài / Species', 'IUCN', 'Surveyor', 'DateTime'
        ])
        self.tbl_data.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.tbl_data.setSelectionBehavior(QAbstractItemView.SelectRows)
        ly.addWidget(self.tbl_data)

        return w

    # ── TAB 2: RESULTS ──
    def _tab_results(self):
        w = QWidget()
        ly = QVBoxLayout(w)

        info = QLabel('Nhấn nút bên dưới để tạo layers từ dữ liệu đã nhập.\n'
                      'Press buttons below to generate layers from entered data.')
        info.setStyleSheet('color:#555; padding:8px;')
        ly.addWidget(info)

        btn_ly = QHBoxLayout()
        self.btn_generate = QPushButton('🔬 Tạo Layers / Generate Layers')
        self.btn_generate.setStyleSheet('background:#1B5E20;color:white;padding:10px 20px;border-radius:6px;font-size:13px;font-weight:bold;')
        self.btn_generate.clicked.connect(self._generate_layers)
        btn_ly.addWidget(self.btn_generate)

        self.btn_tri = QPushButton('🔺 Triangulation')
        self.btn_tri.setStyleSheet('background:#0D47A1;color:white;padding:10px 20px;border-radius:6px;font-size:13px;font-weight:bold;')
        self.btn_tri.clicked.connect(self._do_triangulation)
        btn_ly.addWidget(self.btn_tri)
        ly.addLayout(btn_ly)

        self.tbl_results = QTableWidget(0, 10)
        self.tbl_results.setHorizontalHeaderLabels([
            'ID', 'Lon', 'Lat', 'Est.Lon', 'Est.Lat',
            'Species', 'IUCN', 'Bearing', 'Distance', 'Area(ha)'
        ])
        self.tbl_results.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        ly.addWidget(self.tbl_results)

        return w

    # ── TAB 3: GUIDE ──
    def _tab_guide(self):
        w = QWidget()
        ly = QVBoxLayout(w)
        txt = QTextEdit()
        txt.setReadOnly(True)
        txt.setHtml("""
        <h2>🧭 Hướng dẫn / Guide</h2>
        <h3>Cách đo góc phương vị:</h3>
        <ol>
        <li>Đứng tại vị trí nghe thấy tiếng kêu</li>
        <li>Dùng la bàn, xác định hướng Bắc (0°)</li>
        <li>Xoay theo chiều kim đồng hồ đến hướng âm thanh</li>
        <li>Đọc góc: 0°=Bắc, 90°=Đông, 180°=Nam, 270°=Tây</li>
        </ol>
        <h3>Ước tính khoảng cách:</h3>
        <table border='1' cellpadding='4'>
        <tr><th>Âm thanh</th><th>Gần</th><th>Trung bình</th><th>Xa</th></tr>
        <tr><td>Vượn hú</td><td>200m</td><td>500m</td><td>2000m</td></tr>
        <tr><td>Chim kêu</td><td>50m</td><td>200m</td><td>500m</td></tr>
        <tr><td>Ếch kêu</td><td>10m</td><td>50m</td><td>150m</td></tr>
        <tr><td>Ve sầu</td><td>20m</td><td>100m</td><td>300m</td></tr>
        </table>
        <h3>Triangulation:</h3>
        <p>Chọn 2+ bản ghi cùng loài → nhấn 🔺 Triangulation để giao 2 hướng nghe.</p>
        """)
        ly.addWidget(txt)
        return w

    # ── CALLBACKS ──
    def _on_group_changed(self, group):
        self.cmb_species.clear()
        names = get_vn_names_by_group(group)
        self.cmb_species.addItems(names)

    def _on_species_changed(self, name):
        info = lookup_species(name)
        if info:
            self.lbl_sci.setText(info['name_sci'])
        else:
            self.lbl_sci.setText('—')

    def _collect_record(self):
        info = lookup_species(self.cmb_species.currentText())
        return {
            'longitude': self.spn_lon.value(),
            'latitude': self.spn_lat.value(),
            'bearing_deg': self.spn_bearing.value(),
            'distance_m': self.spn_dist.value(),
            'error_angle_deg': self.spn_aerr.value(),
            'error_distance_pct': self.spn_derr.value(),
            'elevation_m': self.spn_elev.value(),
            'habitat': self.cmb_habitat.currentText(),
            'terrain': self.cmb_terrain.currentText(),
            'species_group': self.cmb_group.currentText(),
            'species_vn': self.cmb_species.currentText(),
            'species_sci': info['name_sci'] if info else '',
            'iucn': info['iucn'] if info else '—',
            'nd84': info['nd84'] if info else '—',
            'count': self.cmb_count.currentText(),
            'datetime': self.dt_time.dateTime().toString('yyyy-MM-dd HH:mm'),
            'surveyor': self.txt_surveyor.text(),
            'patrol_route': self.txt_patrol.text(),
            'weather': self.cmb_weather.currentText(),
            'wind_dir': self.cmb_wind.currentText(),
            'notes': self.txt_notes.text(),
        }

    def _add_record(self):
        rec = self._collect_record()
        if not rec['longitude'] or not rec['latitude']:
            QMessageBox.warning(self, 'Warning', 'Vui lòng nhập toạ độ!')
            return
        self.records.append(rec)
        self._refresh_table()

    def _del_record(self):
        row = self.tbl_data.currentRow()
        if row >= 0 and row < len(self.records):
            self.records.pop(row)
            self._refresh_table()

    def _refresh_table(self):
        self.tbl_data.setRowCount(len(self.records))
        for i, r in enumerate(self.records):
            self.tbl_data.setItem(i, 0, QTableWidgetItem(f"{r['longitude']:.6f}"))
            self.tbl_data.setItem(i, 1, QTableWidgetItem(f"{r['latitude']:.6f}"))
            self.tbl_data.setItem(i, 2, QTableWidgetItem(str(r['bearing_deg'])))
            self.tbl_data.setItem(i, 3, QTableWidgetItem(str(r['distance_m'])))
            self.tbl_data.setItem(i, 4, QTableWidgetItem(r['species_vn']))
            self.tbl_data.setItem(i, 5, QTableWidgetItem(r.get('iucn', '—')))
            self.tbl_data.setItem(i, 6, QTableWidgetItem(r['surveyor']))
            self.tbl_data.setItem(i, 7, QTableWidgetItem(r['datetime']))

    def _export_template(self):
        path, _ = QFileDialog.getSaveFileName(
            self, 'Export Template', 'WSL_Template.xlsx',
            'Excel (*.xlsx)')
        if path:
            try:
                export_template(path)
                QMessageBox.information(self, '✅', f'Template exported:\n{path}')
            except Exception as e:
                QMessageBox.critical(self, 'Error', str(e))

    def _import_template(self):
        path, _ = QFileDialog.getOpenFileName(
            self, 'Import Excel', '', 'Excel (*.xlsx)')
        if path:
            try:
                imported = import_template(path)
                self.records.extend(imported)
                self._refresh_table()
                QMessageBox.information(
                    self, '✅', f'Imported {len(imported)} records.')
            except Exception as e:
                QMessageBox.critical(self, 'Error', str(e))

    # ── LAYER GENERATION ──
    def _generate_layers(self):
        if not self.records:
            QMessageBox.warning(self, 'Warning', 'Chưa có dữ liệu!')
            return

        _ = QgsCoordinateReferenceSystem('EPSG:4326')
        ts = datetime.datetime.now().strftime('%H%M%S')

        # Fields
        flds_str = ('observer_id species_vn species_sci iucn nd84 '
                    'species_group count habitat terrain weather '
                    'wind_dir surveyor patrol_route datetime notes').split()
        flds_num = 'longitude latitude bearing_deg distance_m elevation_m error_angle_deg error_distance_pct'.split()

        def make_fields():
            fields = QgsFields()
            fields.append(QgsField('fid', QVariant.Int))
            for f in flds_str:
                fields.append(QgsField(f, QVariant.String))
            for f in flds_num:
                fields.append(QgsField(f, QVariant.Double))
            fields.append(QgsField('area_ha', QVariant.Double))
            return fields

        fields = make_fields()

        # Observer Points
        lyr_obs = QgsVectorLayer('Point?crs=EPSG:4326', f'WSL_Observers_{ts}', 'memory')
        lyr_est = QgsVectorLayer('Point?crs=EPSG:4326', f'WSL_Estimated_{ts}', 'memory')
        lyr_line = QgsVectorLayer('LineString?crs=EPSG:4326', f'WSL_Bearings_{ts}', 'memory')
        lyr_zone = QgsVectorLayer('Polygon?crs=EPSG:4326', f'WSL_Confidence_{ts}', 'memory')

        for lyr in [lyr_obs, lyr_est, lyr_line, lyr_zone]:
            lyr.dataProvider().addAttributes(fields.toList())
            lyr.updateFields()

        feats_obs, feats_est, feats_line, feats_zone = [], [], [], []

        for i, rec in enumerate(self.records):
            fid = i + 1
            lon = float(rec['longitude'])
            lat = float(rec['latitude'])
            brg = float(rec['bearing_deg'])
            dist = float(rec['distance_m'])
            aerr = float(rec.get('error_angle_deg', 15))
            derr = float(rec.get('error_distance_pct', 30))

            # Common attributes
            attrs = [fid]
            attrs.append(f'OBS{fid:03d}')
            for f in flds_str[1:]:
                attrs.append(str(rec.get(f, '')))
            for f in flds_num:
                attrs.append(float(rec.get(f, 0)))
            area = sector_area_ha(dist, aerr, derr)
            attrs.append(round(area, 4))

            # Observer point
            feat_o = QgsFeature(fields)
            feat_o.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(lon, lat)))
            feat_o.setAttributes(attrs)
            feats_obs.append(feat_o)

            # Estimated point
            est_lat, est_lon = destination_point(lat, lon, brg, dist)
            feat_e = QgsFeature(fields)
            feat_e.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(est_lon, est_lat)))
            feat_e.setAttributes(attrs)
            feats_est.append(feat_e)

            # Bearing line
            line_coords = bearing_line_coords(lat, lon, brg, dist)
            points = [QgsPointXY(x, y) for x, y in line_coords]
            feat_l = QgsFeature(fields)
            feat_l.setGeometry(QgsGeometry.fromPolylineXY(points))
            feat_l.setAttributes(attrs)
            feats_line.append(feat_l)

            # Confidence sector
            sector_coords = confidence_sector_coords(
                lat, lon, brg, dist, aerr, derr)
            poly_pts = [QgsPointXY(x, y) for x, y in sector_coords]
            feat_z = QgsFeature(fields)
            feat_z.setGeometry(QgsGeometry.fromPolygonXY([poly_pts]))
            feat_z.setAttributes(attrs)
            feats_zone.append(feat_z)

        lyr_obs.dataProvider().addFeatures(feats_obs)
        lyr_est.dataProvider().addFeatures(feats_est)
        lyr_line.dataProvider().addFeatures(feats_line)
        lyr_zone.dataProvider().addFeatures(feats_zone)

        for lyr in [lyr_zone, lyr_line, lyr_obs, lyr_est]:
            lyr.updateExtents()
            QgsProject.instance().addMapLayer(lyr)

        # Update results table
        self.tbl_results.setRowCount(len(self.records))
        for i, rec in enumerate(self.records):
            lon = float(rec['longitude'])
            lat = float(rec['latitude'])
            brg = float(rec['bearing_deg'])
            dist = float(rec['distance_m'])
            est_lat, est_lon = destination_point(lat, lon, brg, dist)
            area = sector_area_ha(dist,
                                  float(rec.get('error_angle_deg', 15)),
                                                float(rec.get('error_distance_pct', 30)))  # noqa: E127
            vals = [f'OBS{i+1:03d}', f'{lon:.6f}', f'{lat:.6f}',  # noqa: E226
                    f'{est_lon:.6f}', f'{est_lat:.6f}',
                    rec['species_vn'], rec.get('iucn', '—'),
                    str(brg), str(dist), f'{area:.4f}']
            for j, v in enumerate(vals):
                self.tbl_results.setItem(i, j, QTableWidgetItem(v))

        self.tabs.setCurrentIndex(1)
        self.iface.messageBar().pushSuccess(
            'WSL', f'✅ Created 4 layers with {len(self.records)} records')

    def _do_triangulation(self):
        rows = set(idx.row() for idx in self.tbl_data.selectedIndexes())
        if len(rows) < 2:
            QMessageBox.warning(self, 'Triangulation',
                                'Chọn ít nhất 2 bản ghi / Select at least 2 records')
            return
        row_list = sorted(rows)
        r1 = self.records[row_list[0]]
        r2 = self.records[row_list[1]]

        result = triangulate(
            float(r1['latitude']), float(r1['longitude']),
            float(r1['bearing_deg']),
            float(r2['latitude']), float(r2['longitude']),
            float(r2['bearing_deg']))

        if result is None:
            QMessageBox.warning(self, 'Triangulation',
                                'Không tìm được điểm giao / No intersection found')
            return

        tri_lat, tri_lon = result
        ts = datetime.datetime.now().strftime('%H%M%S')
        lyr = QgsVectorLayer('Point?crs=EPSG:4326',
                             f'WSL_Triangulated_{ts}', 'memory')
        flds = QgsFields()
        flds.append(QgsField('tri_id', QVariant.Int))
        flds.append(QgsField('obs1', QVariant.String))
        flds.append(QgsField('obs2', QVariant.String))
        flds.append(QgsField('species', QVariant.String))
        flds.append(QgsField('longitude', QVariant.Double))
        flds.append(QgsField('latitude', QVariant.Double))
        lyr.dataProvider().addAttributes(flds.toList())
        lyr.updateFields()

        feat = QgsFeature(flds)
        feat.setGeometry(QgsGeometry.fromPointXY(
            QgsPointXY(tri_lon, tri_lat)))
        feat.setAttributes([1,
                            f"OBS{row_list[0] + 1:03d}",  # noqa: E226
                            f"OBS{row_list[1] + 1:03d}",  # noqa: E226
                            r1['species_vn'], tri_lon, tri_lat])
        lyr.dataProvider().addFeatures([feat])
        lyr.updateExtents()
        QgsProject.instance().addMapLayer(lyr)

        QMessageBox.information(self, '🔺 Triangulation',
                                f'Điểm giao: {tri_lat:.6f}, {tri_lon:.6f}')
