#![allow(unused_imports)]

use axum::{
    body::Body,
    http::{self, Request, StatusCode},
    response::Response,
};
use data_persistence_service::{
    self as app,
    dtos::{
        CompanyProfileDto, DailyMarketDataBatchDto, DailyMarketDataDto,
        TimeSeriesFinancialBatchDto, TimeSeriesFinancialDto,
    },
    AppState,
};
use http_body_util::BodyExt;
use sqlx::PgPool;
use tower::util::ServiceExt; // for `oneshot`
use uuid::Uuid;

// Note: We need to make `build_rest_router` and `AppState` public in lib.rs and main.rs respectively.
// This test structure assumes that has been done.

#[sqlx::test]
async fn test_api_upsert_and_get_company(pool: PgPool) {
    let state = AppState::new(pool);
    let openapi = app::build_openapi_spec();
    let app = app::build_rest_router_with_state(openapi, state).unwrap();

    // 1. Act: Upsert a new company
    let new_company = CompanyProfileDto {
        symbol: "API.TEST".to_string(),
        name: "API Test Corp".to_string(),
        industry: Some("API Testing".to_string()),
        list_date: Some(chrono::NaiveDate::from_ymd_opt(2025, 1, 1).unwrap()),
        additional_info: None,
        updated_at: None,
    };

    let request = Request::builder()
        .method("PUT")
        .uri("/api/v1/companies")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_string(&new_company).unwrap()))
        .unwrap();

    let response = ServiceExt::oneshot(app.clone().into_service(), request).await.unwrap();
    assert_eq!(response.status(), StatusCode::OK);

    // 2. Act: Get the company
    let request_get = Request::builder()
        .method("GET")
        .uri("/api/v1/companies/API.TEST")
        .body(Body::empty())
        .unwrap();
    
    let response_get = ServiceExt::oneshot(app.clone().into_service(), request_get).await.unwrap();
    assert_eq!(response_get.status(), StatusCode::OK);

    // 3. Assert: Check the response body
    let body = response_get.into_body().collect().await.unwrap().to_bytes();
    let fetched_company: CompanyProfileDto = serde_json::from_slice(&body).unwrap();
    
    assert_eq!(fetched_company.symbol, new_company.symbol);
    assert_eq!(fetched_company.name, new_company.name);
}

#[sqlx::test]
async fn test_api_batch_insert_and_get_financials(pool: PgPool) {
    let state = AppState::new(pool);
    let openapi = app::build_openapi_spec();
    let app = app::build_rest_router_with_state(openapi, state).unwrap();

    // 1. Act: Batch insert financials
    let financials = TimeSeriesFinancialBatchDto {
        records: vec![
            TimeSeriesFinancialDto {
                symbol: "API.FIN".to_string(),
                metric_name: "revenue".to_string(),
                period_date: chrono::NaiveDate::from_ymd_opt(2023, 12, 31).unwrap(),
                value: 2000.0,
                source: Some("api_test".to_string()),
            },
        ],
    };

    let request = Request::builder()
        .method("POST")
        .uri("/api/v1/market-data/financials/batch")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_string(&financials).unwrap()))
        .unwrap();

    let response = ServiceExt::oneshot(app.clone().into_service(), request).await.unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);

    // 2. Act: Get the financials
    let request_get = Request::builder()
        .method("GET")
        .uri("/api/v1/market-data/financials/API.FIN?metrics=revenue")
        .body(Body::empty())
        .unwrap();

    let response_get = ServiceExt::oneshot(app.clone().into_service(), request_get).await.unwrap();
    assert_eq!(response_get.status(), StatusCode::OK);

    // 3. Assert: Check the response body
    let body = response_get.into_body().collect().await.unwrap().to_bytes();
    let fetched_financials: Vec<TimeSeriesFinancialDto> = serde_json::from_slice(&body).unwrap();
    
    assert_eq!(fetched_financials.len(), 1);
    assert_eq!(fetched_financials[0].symbol, "API.FIN");
    assert_eq!(fetched_financials[0].metric_name, "revenue");
    assert_eq!(fetched_financials[0].value, 2000.0);
}

#[sqlx::test]
async fn test_api_batch_insert_and_get_daily(pool: PgPool) {
    let state = AppState::new(pool);
    let openapi = app::build_openapi_spec();
    let app = app::build_rest_router_with_state(openapi, state).unwrap();

    // 1. Act: Batch insert daily data
    let daily_data = DailyMarketDataBatchDto {
        records: vec![
            DailyMarketDataDto {
                symbol: "API.DAILY".to_string(),
                trade_date: chrono::NaiveDate::from_ymd_opt(2024, 1, 5).unwrap(),
                close_price: Some(250.5),
                // ... other fields are None
                open_price: None,
                high_price: None,
                low_price: None,
                volume: None,
                pe: None,
                pb: None,
                total_mv: None,
            },
        ],
    };

    let request = Request::builder()
        .method("POST")
        .uri("/api/v1/market-data/daily/batch")
        .header("content-type", "application/json")
        .body(Body::from(serde_json::to_string(&daily_data).unwrap()))
        .unwrap();
    
    let response = ServiceExt::oneshot(app.clone().into_service(), request).await.unwrap();
    assert_eq!(response.status(), StatusCode::CREATED);

    // 2. Act: Get the daily data
    let request_get = Request::builder()
        .method("GET")
        .uri("/api/v1/market-data/daily/API.DAILY")
        .body(Body::empty())
        .unwrap();
    
    let response_get = ServiceExt::oneshot(app.clone().into_service(), request_get).await.unwrap();
    assert_eq!(response_get.status(), StatusCode::OK);

    // 3. Assert: Check the response body
    let body = response_get.into_body().collect().await.unwrap().to_bytes();
    let fetched_data: Vec<DailyMarketDataDto> = serde_json::from_slice(&body).unwrap();
    
    assert_eq!(fetched_data.len(), 1);
    assert_eq!(fetched_data[0].symbol, "API.DAILY");
    assert_eq!(fetched_data[0].close_price, Some(250.5));
}

