use chrono::DateTime;
use thiserror::Error;

use crate::gitlab::types::GitLabIssue;

#[derive(Debug, Error)]
pub enum TransformError {
    #[error("Failed to parse timestamp '{0}': {1}")]
    TimestampParse(String, String),
}

#[derive(Debug, Clone)]
pub struct IssueRow {
    pub gitlab_id: i64,
    pub iid: i64,
    pub project_id: i64,
    pub title: String,
    pub description: Option<String>,
    pub state: String,
    pub author_username: String,
    pub created_at: i64,
    pub updated_at: i64,
    pub web_url: String,
    pub due_date: Option<String>,
    pub milestone_title: Option<String>,
}

#[derive(Debug, Clone)]
pub struct MilestoneRow {
    pub gitlab_id: i64,
    pub project_id: i64,
    pub iid: i64,
    pub title: String,
    pub description: Option<String>,
    pub state: Option<String>,
    pub due_date: Option<String>,
    pub web_url: Option<String>,
}

#[derive(Debug, Clone)]
pub struct IssueWithMetadata {
    pub issue: IssueRow,
    pub label_names: Vec<String>,
    pub assignee_usernames: Vec<String>,
    pub milestone: Option<MilestoneRow>,
}

fn parse_timestamp(ts: &str) -> Result<i64, TransformError> {
    DateTime::parse_from_rfc3339(ts)
        .map(|dt| dt.timestamp_millis())
        .map_err(|e| TransformError::TimestampParse(ts.to_string(), e.to_string()))
}

pub fn transform_issue(issue: &GitLabIssue) -> Result<IssueWithMetadata, TransformError> {
    let created_at = parse_timestamp(&issue.created_at)?;
    let updated_at = parse_timestamp(&issue.updated_at)?;

    let assignee_usernames: Vec<String> =
        issue.assignees.iter().map(|a| a.username.clone()).collect();

    let milestone_title = issue.milestone.as_ref().map(|m| m.title.clone());

    let milestone = issue.milestone.as_ref().map(|m| MilestoneRow {
        gitlab_id: m.id,
        project_id: m.project_id.unwrap_or(issue.project_id),
        iid: m.iid,
        title: m.title.clone(),
        description: m.description.clone(),
        state: m.state.clone(),
        due_date: m.due_date.clone(),
        web_url: m.web_url.clone(),
    });

    Ok(IssueWithMetadata {
        issue: IssueRow {
            gitlab_id: issue.id,
            iid: issue.iid,
            project_id: issue.project_id,
            title: issue.title.clone(),
            description: issue.description.clone(),
            state: issue.state.clone(),
            author_username: issue.author.username.clone(),
            created_at,
            updated_at,
            web_url: issue.web_url.clone(),
            due_date: issue.due_date.clone(),
            milestone_title,
        },
        label_names: issue.labels.clone(),
        assignee_usernames,
        milestone,
    })
}

#[cfg(test)]
#[path = "issue_tests.rs"]
mod tests;
