"""Service for tracking dataset uploads to organizations."""

import yaml
import uuid
from datetime import datetime
from typing import List, Optional, Dict, Any

from ..s3_data_service import S3DataService
from .models import UploadEvent


class UploadTrackingService:
    """Service for tracking upload events per organization."""

    def __init__(self, s3_service: S3DataService):
        self.s3_service = s3_service

    def record_upload(self, upload_event: UploadEvent) -> None:
        """
        Record an upload event for an organization.

        Args:
            upload_event: The upload event to record
        """
        uploads_path = f"piedpiper-custom-billing/{upload_event.organization}/upload_tracking.yaml"

        try:
            # Load existing uploads
            existing_uploads = self._load_organization_uploads(upload_event.organization)

            # Add new upload event
            existing_uploads.append(upload_event)

            # Save updated uploads
            self._save_organization_uploads(upload_event.organization, existing_uploads)

        except Exception as e:
            # Upload tracking failure shouldn't block uploads, but log it
            # In a real system, you might want more robust error handling
            pass

    def get_upload_history(self, organization: str) -> List[UploadEvent]:
        """
        Get upload history for an organization.

        Args:
            organization: Organization name

        Returns:
            List of upload events, newest first
        """
        uploads = self._load_organization_uploads(organization)

        # Sort by upload time, newest first
        return sorted(uploads, key=lambda x: x.uploaded_at, reverse=True)

    def get_drop_upload_composition(self, organization: str, provider: str, date_range: str) -> List[UploadEvent]:
        """
        Get upload events that contributed to a specific billing drop.

        Args:
            organization: Organization name
            provider: Provider (AWS, GCP, Azure)
            date_range: Date range in format YYYYMMDD-YYYYMMDD

        Returns:
            List of upload events that contributed to this drop
        """
        all_uploads = self.get_upload_history(organization)

        # Filter uploads that match the provider and could have contributed to this date range
        relevant_uploads = []

        for upload in all_uploads:
            # Check if this upload included the provider
            if provider in upload.providers_uploaded:
                # Check if any of the upload months overlap with the date range
                # This is a simplified check - in practice you might want more sophisticated logic
                if self._upload_contributes_to_date_range(upload, date_range):
                    relevant_uploads.append(upload)

        return relevant_uploads

    def get_latest_upload_for_organization(self, organization: str) -> Optional[UploadEvent]:
        """
        Get the most recent upload event for an organization.

        This represents the current active billing drop for the organization.

        Args:
            organization: Organization name

        Returns:
            Most recent UploadEvent or None if no uploads found
        """
        uploads = self.get_upload_history(organization)
        return uploads[0] if uploads else None

    def create_upload_event(
        self,
        dataset_id: str,
        organization: str,
        upload_type: str,
        providers_uploaded: List[str],
        months_uploaded: List[str],
        date_range_folder: str,
        drop_id: str
    ) -> UploadEvent:
        """
        Create a new upload event.

        Args:
            dataset_id: ID of the dataset being uploaded
            organization: Target organization
            upload_type: "new" or "append"
            providers_uploaded: List of providers (AWS, GCP, Azure)
            months_uploaded: List of months in YYYY-MM format
            date_range_folder: The date range folder name (e.g., "20241001-20241231")
            drop_id: The drop ID for this upload

        Returns:
            Created UploadEvent
        """
        upload_id = str(uuid.uuid4())[:8]  # Short UUID for readability

        return UploadEvent(
            upload_id=upload_id,
            dataset_id=dataset_id,
            organization=organization,
            uploaded_at=datetime.now(),
            upload_type=upload_type,
            providers_uploaded=providers_uploaded,
            months_uploaded=months_uploaded,
            date_range_folder=date_range_folder,
            drop_id=drop_id
        )

    def _load_organization_uploads(self, organization: str) -> List[UploadEvent]:
        """Load existing uploads for an organization."""
        uploads_path = f"piedpiper-custom-billing/{organization}/upload_tracking.yaml"

        try:
            uploads_content = self.s3_service.read_text_file(uploads_path)
            uploads_data = yaml.safe_load(uploads_content)

            if not uploads_data or 'uploads' not in uploads_data:
                return []

            # Convert dictionaries back to UploadEvent objects
            upload_events = []
            for upload_dict in uploads_data['uploads']:
                upload_event = UploadEvent(
                    upload_id=upload_dict['upload_id'],
                    dataset_id=upload_dict['dataset_id'],
                    organization=upload_dict['organization'],
                    uploaded_at=datetime.fromisoformat(upload_dict['uploaded_at'].replace('Z', '+00:00')),
                    upload_type=upload_dict['upload_type'],
                    providers_uploaded=upload_dict['providers_uploaded'],
                    months_uploaded=upload_dict['months_uploaded'],
                    date_range_folder=upload_dict['date_range_folder'],
                    drop_id=upload_dict.get('drop_id', 'unknown')  # Handle legacy data
                )
                upload_events.append(upload_event)

            return upload_events

        except Exception:
            return []

    def _save_organization_uploads(self, organization: str, uploads: List[UploadEvent]) -> None:
        """Save uploads for an organization."""
        uploads_path = f"piedpiper-custom-billing/{organization}/upload_tracking.yaml"

        # Convert UploadEvent objects to dictionaries
        uploads_data = {
            'organization': organization,
            'last_updated': datetime.now().isoformat() + 'Z',
            'uploads': []
        }

        for upload in uploads:
            upload_dict = {
                'upload_id': upload.upload_id,
                'dataset_id': upload.dataset_id,
                'organization': upload.organization,
                'uploaded_at': upload.uploaded_at.isoformat() + 'Z',
                'upload_type': upload.upload_type,
                'providers_uploaded': upload.providers_uploaded,
                'months_uploaded': upload.months_uploaded,
                'date_range_folder': upload.date_range_folder,
                'drop_id': upload.drop_id
            }
            uploads_data['uploads'].append(upload_dict)

        # Save to S3
        yaml_content = yaml.dump(uploads_data, default_flow_style=False, sort_keys=True)
        self.s3_service.upload_text_content(uploads_path, yaml_content)

    def _upload_contributes_to_date_range(self, upload: UploadEvent, date_range: str) -> bool:
        """
        Check if an upload contributes to a specific date range.

        This is a simplified implementation - in practice you might want more
        sophisticated logic to match date ranges with upload months.

        Args:
            upload: Upload event to check
            date_range: Date range in format YYYYMMDD-YYYYMMDD

        Returns:
            True if upload could contribute to this date range
        """
        try:
            # Extract year-month from upload months
            upload_months = set(upload.months_uploaded)

            # Extract year-months from date range
            # Format: YYYYMMDD-YYYYMMDD -> extract months covered
            start_date, end_date = date_range.split('-')

            start_year = int(start_date[:4])
            start_month = int(start_date[4:6])
            end_year = int(end_date[:4])
            end_month = int(end_date[4:6])

            # Generate all months in the date range
            date_range_months = set()
            current_year = start_year
            current_month = start_month

            while (current_year < end_year) or (current_year == end_year and current_month <= end_month):
                date_range_months.add(f"{current_year:04d}-{current_month:02d}")

                current_month += 1
                if current_month > 12:
                    current_month = 1
                    current_year += 1

            # Check if any upload months overlap with date range months
            return bool(upload_months.intersection(date_range_months))

        except Exception:
            # If parsing fails, assume it could contribute (conservative approach)
            return True

    def list_organizations_with_uploads(self) -> List[str]:
        """List all organizations that have upload tracking data."""
        tracking_prefix = "czbillgen/upload-tracking/"

        try:
            folders = self.s3_service.list_folders(tracking_prefix)
            organizations = []

            for folder in folders:
                # Extract organization name from folder path
                org_name = folder.rstrip('/').split('/')[-1]
                if org_name:
                    organizations.append(org_name)

            return sorted(organizations)

        except Exception:
            return []