//! Google Play Developer API publisher.
//!
//! Models the Google Play Developer API calls. Stubs the actual HTTP.
//!
//! API reference: https://developers.google.com/android-publisher

use crate::{
    config::{GoogleConfig, PublishConfig},
    metadata::StoreMetadata,
    PublishError, PublishOutcome, PublishResult,
};

/// Publishes app bundles to Google Play Store.
pub struct GooglePublisher {
    pub google_config: GoogleConfig,
    pub publish_config: PublishConfig,
}

impl GooglePublisher {
    pub fn new(publish_config: PublishConfig) -> PublishResult<Self> {
        let google_config = publish_config.google.clone().ok_or_else(|| {
            PublishError::Config("no [publish.google] section in el.toml".into())
        })?;
        Ok(Self { google_config, publish_config })
    }

    /// Create a new edit session on Google Play.
    ///
    /// In production: POST https://androidpublisher.googleapis.com/v3/applications/{packageName}/edits
    pub fn create_edit(&self) -> PublishResult<String> {
        // TODO: OAuth2 authentication via service account JSON
        let edit_id = format!("edit-{}", self.publish_config.build_number);
        Ok(edit_id)
    }

    /// Upload an AAB (Android App Bundle) to an edit session.
    ///
    /// In production: POST .../edits/{editId}/bundles (multipart upload)
    pub fn upload_bundle(
        &self,
        edit_id: &str,
        aab_path: &str,
    ) -> PublishResult<u32> {
        let _ = (edit_id, aab_path);
        // Returns the version code of the uploaded bundle
        Ok(self.publish_config.build_number)
    }

    /// Assign a bundle to a track.
    ///
    /// In production: PUT .../edits/{editId}/tracks/{track}
    pub fn assign_to_track(
        &self,
        edit_id: &str,
        version_code: u32,
        track: &str,
        rollout_fraction: f64,
    ) -> PublishResult<()> {
        let _ = (edit_id, version_code, track, rollout_fraction);
        if !matches!(track, "internal" | "alpha" | "beta" | "production") {
            return Err(PublishError::Config(format!(
                "unknown Google Play track: '{}'. Use internal/alpha/beta/production",
                track
            )));
        }
        Ok(())
    }

    /// Upload store listing (metadata) for a locale.
    ///
    /// In production: PATCH .../edits/{editId}/listings/{language}
    pub fn upload_listing(
        &self,
        edit_id: &str,
        locale: &str,
        metadata: &StoreMetadata,
    ) -> PublishResult<()> {
        let _ = (edit_id, locale, metadata);
        Ok(())
    }

    /// Commit an edit (makes the changes live).
    ///
    /// In production: POST .../edits/{editId}:commit
    pub fn commit_edit(&self, edit_id: &str) -> PublishResult<String> {
        // Returns the resulting version code
        Ok(format!("{}-committed", edit_id))
    }

    /// Update rollout percentage for a track (for staged rollouts).
    pub fn update_rollout(&self, track: &str, percent: u8) -> PublishResult<()> {
        if percent > 100 {
            return Err(PublishError::Config(format!(
                "rollout percent {} exceeds 100",
                percent
            )));
        }
        let _ = (track, percent);
        // TODO: PATCH .../tracks/{track} with rollout fraction
        Ok(())
    }

    /// Full publish flow: create edit → upload bundle → assign to track → commit.
    pub fn publish(&self, aab_path: &str) -> PublishResult<PublishOutcome> {
        let metadata = StoreMetadata::load_from_dir(&self.publish_config.metadata_dir)?;
        let edit_id = self.create_edit()?;
        let version_code = self.upload_bundle(&edit_id, aab_path)?;

        let track = &self.google_config.track;
        let rollout_fraction = self
            .publish_config
            .rollout
            .as_ref()
            .map(|r| r.initial_percent as f64 / 100.0)
            .unwrap_or(1.0);

        self.assign_to_track(&edit_id, version_code, track, rollout_fraction)?;
        self.upload_listing(&edit_id, "en-US", &metadata)?;
        let commit_id = self.commit_edit(&edit_id)?;

        Ok(PublishOutcome::new("google", &self.publish_config, track)
            .with_submission_id(commit_id))
    }
}
