from odoo import models, fields, api
from math import radians, sin, cos, sqrt, atan2


class WtLocationLog(models.Model):
    _name = 'wt.location.log'
    _description = 'WorkTrace Location Log'
    _order = 'arrived_at asc'

    name = fields.Char(
        string='Location',
        compute='_compute_name',
        store=True
    )
    date = fields.Date(string='Date', required=True, index=True)
    arrived_at = fields.Datetime(string='Arrived At', required=True)
    departed_at = fields.Datetime(string='Departed At')

    latitude = fields.Float(string='Latitude', digits=(10, 7))
    longitude = fields.Float(string='Longitude', digits=(10, 7))
    address = fields.Char(string='Address')
    place_name = fields.Char(string='Place / Business Name')

    time_at_location = fields.Float(
        string='Time at Location (hrs)',
        compute='_compute_time_at_location',
        store=True
    )
    distance_from_previous = fields.Float(
        string='Distance from Previous (mi)',
        digits=(10, 2)
    )
    travel_time_from_previous = fields.Float(
        string='Travel Time from Previous (hrs)',
        digits=(10, 2)
    )
    travel_mode = fields.Selection([
        ('driving', 'Driving'),
        ('walking', 'Walking'),
        ('transit', 'Transit'),
        ('unknown', 'Unknown'),
    ], string='Travel Mode', default='unknown')

    source = fields.Selection([
        ('google_timeline', 'Google Timeline'),
        ('manual', 'Manual'),
    ], string='Source', default='google_timeline')

    calendar_event_id = fields.Many2one(
        'calendar.event',
        string='Calendar Event',
        ondelete='set null'
    )
    add_to_calendar = fields.Boolean(string='Add to Calendar', default=True)
    notes = fields.Text(string='Notes')

    @api.depends('address', 'place_name', 'latitude', 'longitude')
    def _compute_name(self):
        for rec in self:
            rec.name = (
                rec.place_name
                or rec.address
                or (f'{rec.latitude:.5f}, {rec.longitude:.5f}' if rec.latitude else 'Unknown Location')
            )

    @api.depends('arrived_at', 'departed_at')
    def _compute_time_at_location(self):
        for rec in self:
            if rec.arrived_at and rec.departed_at:
                delta = rec.departed_at - rec.arrived_at
                rec.time_at_location = delta.total_seconds() / 3600
            else:
                rec.time_at_location = 0.0

    @staticmethod
    def _haversine_distance(lat1, lon1, lat2, lon2):
        """Calculate distance in miles between two GPS coordinates."""
        R = 3958.8  # Earth radius in miles
        lat1, lon1, lat2, lon2 = map(radians, [lat1, lon1, lat2, lon2])
        dlat = lat2 - lat1
        dlon = lon2 - lon1
        a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
        return R * 2 * atan2(sqrt(a), sqrt(1 - a))

    def action_geocode(self):
        """Resolve coordinates to address using OpenStreetMap Nominatim."""
        import requests
        for rec in self:
            if not rec.latitude or not rec.longitude:
                continue
            url = 'https://nominatim.openstreetmap.org/reverse'
            params = {
                'lat': rec.latitude,
                'lon': rec.longitude,
                'format': 'json',
                'addressdetails': 1,
            }
            headers = {'User-Agent': 'WorkTrace/1.0 (Odoo Module)'}
            try:
                resp = requests.get(url, params=params, headers=headers, timeout=10)
                resp.raise_for_status()
                result = resp.json()
                rec.address = result.get('display_name', '')
                rec.place_name = (
                    result.get('name')
                    or result.get('address', {}).get('amenity')
                    or result.get('address', {}).get('shop')
                    or result.get('address', {}).get('building')
                    or ''
                )
            except Exception:
                pass

    def action_compute_distances(self):
        """Compute distances and travel times between sequential location logs for the same date."""
        dates = self.mapped('date')
        for date in set(dates):
            logs = self.search([('date', '=', date)], order='arrived_at asc')
            prev = None
            for log in logs:
                if prev and prev.latitude and log.latitude:
                    log.distance_from_previous = self._haversine_distance(
                        prev.latitude, prev.longitude,
                        log.latitude, log.longitude
                    )
                    if prev.departed_at and log.arrived_at:
                        delta = log.arrived_at - prev.departed_at
                        log.travel_time_from_previous = max(delta.total_seconds() / 3600, 0)
                prev = log
