package kr.co.vividnext.sodalive.di

import android.content.Context
import com.google.gson.GsonBuilder
import kr.co.vividnext.sodalive.BuildConfig
import kr.co.vividnext.sodalive.audio_content.AudioContentApi
import kr.co.vividnext.sodalive.audio_content.AudioContentRepository
import kr.co.vividnext.sodalive.audio_content.AudioContentViewModel
import kr.co.vividnext.sodalive.audio_content.PlaybackTrackingRepository
import kr.co.vividnext.sodalive.audio_content.all.AudioContentNewAllViewModel
import kr.co.vividnext.sodalive.audio_content.all.AudioContentRankingAllViewModel
import kr.co.vividnext.sodalive.audio_content.all.by_theme.AudioContentAllByThemeViewModel
import kr.co.vividnext.sodalive.audio_content.category.CategoryApi
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentListViewModel
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentReplyViewModel
import kr.co.vividnext.sodalive.audio_content.comment.AudioContentCommentRepository
import kr.co.vividnext.sodalive.audio_content.curation.AudioContentCurationViewModel
import kr.co.vividnext.sodalive.audio_content.detail.AudioContentDetailViewModel
import kr.co.vividnext.sodalive.audio_content.main.banner.AudioContentMainBannerViewModel
import kr.co.vividnext.sodalive.audio_content.main.curation.AudioContentMainCurationViewModel
import kr.co.vividnext.sodalive.audio_content.main.new_content.AudioContentMainNewContentViewModel
import kr.co.vividnext.sodalive.audio_content.main.order.AudioContentMainOrderListViewModel
import kr.co.vividnext.sodalive.audio_content.main.ranking.AudioContentMainRankingViewModel
import kr.co.vividnext.sodalive.audio_content.main.recommend_series.AudioContentMainRecommendSeriesViewModel
import kr.co.vividnext.sodalive.audio_content.modify.AudioContentModifyViewModel
import kr.co.vividnext.sodalive.audio_content.order.AudioContentOrderListViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistRepository
import kr.co.vividnext.sodalive.audio_content.playlist.AudioContentPlaylistListViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.PlaylistApi
import kr.co.vividnext.sodalive.audio_content.playlist.create.AudioContentPlaylistCreateViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.detail.AudioContentPlaylistDetailViewModel
import kr.co.vividnext.sodalive.audio_content.playlist.modify.AudioContentPlaylistModifyViewModel
import kr.co.vividnext.sodalive.audio_content.series.SeriesApi
import kr.co.vividnext.sodalive.audio_content.series.SeriesListAllViewModel
import kr.co.vividnext.sodalive.audio_content.series.SeriesRepository
import kr.co.vividnext.sodalive.audio_content.series.content.SeriesContentAllViewModel
import kr.co.vividnext.sodalive.audio_content.series.detail.SeriesDetailViewModel
import kr.co.vividnext.sodalive.audio_content.upload.AudioContentUploadViewModel
import kr.co.vividnext.sodalive.audio_content.upload.theme.AudioContentThemeViewModel
import kr.co.vividnext.sodalive.common.ApiBuilder
import kr.co.vividnext.sodalive.common.ObjectBox
import kr.co.vividnext.sodalive.explorer.ExplorerApi
import kr.co.vividnext.sodalive.explorer.ExplorerRepository
import kr.co.vividnext.sodalive.explorer.ExplorerViewModel
import kr.co.vividnext.sodalive.explorer.profile.UserProfileViewModel
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityApi
import kr.co.vividnext.sodalive.explorer.profile.creator_community.CreatorCommunityRepository
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.CreatorCommunityAllViewModel
import kr.co.vividnext.sodalive.explorer.profile.creator_community.all.comment.CreatorCommunityCommentListViewModel
import kr.co.vividnext.sodalive.explorer.profile.creator_community.modify.CreatorCommunityModifyViewModel
import kr.co.vividnext.sodalive.explorer.profile.creator_community.write.CreatorCommunityWriteViewModel
import kr.co.vividnext.sodalive.explorer.profile.donation.UserProfileDonationAllViewModel
import kr.co.vividnext.sodalive.explorer.profile.fantalk.UserProfileFantalkAllViewModel
import kr.co.vividnext.sodalive.explorer.profile.follow.UserFollowerListViewModel
import kr.co.vividnext.sodalive.following.FollowingCreatorRepository
import kr.co.vividnext.sodalive.following.FollowingCreatorViewModel
import kr.co.vividnext.sodalive.live.LiveApi
import kr.co.vividnext.sodalive.live.LiveRepository
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendApi
import kr.co.vividnext.sodalive.live.recommend.LiveRecommendRepository
import kr.co.vividnext.sodalive.live.reservation_status.LiveReservationStatusViewModel
import kr.co.vividnext.sodalive.live.room.LiveRoomViewModel
import kr.co.vividnext.sodalive.live.room.create.LiveRoomCreateViewModel
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailViewModel
import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessageViewModel
import kr.co.vividnext.sodalive.live.room.menu.MenuApi
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigRepository
import kr.co.vividnext.sodalive.live.room.menu.MenuConfigViewModel
import kr.co.vividnext.sodalive.live.room.tag.LiveTagRepository
import kr.co.vividnext.sodalive.live.room.tag.LiveTagViewModel
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditViewModel
import kr.co.vividnext.sodalive.live.roulette.RouletteRepository
import kr.co.vividnext.sodalive.live.roulette.config.RouletteApi
import kr.co.vividnext.sodalive.live.roulette.config.RouletteSettingsViewModel
import kr.co.vividnext.sodalive.main.MainViewModel
import kr.co.vividnext.sodalive.message.MessageApi
import kr.co.vividnext.sodalive.message.MessageRepository
import kr.co.vividnext.sodalive.message.SelectMessageRecipientViewModel
import kr.co.vividnext.sodalive.message.text.TextMessageDetailViewModel
import kr.co.vividnext.sodalive.message.text.TextMessageViewModel
import kr.co.vividnext.sodalive.message.text.TextMessageWriteViewModel
import kr.co.vividnext.sodalive.message.voice.VoiceMessageViewModel
import kr.co.vividnext.sodalive.message.voice.VoiceMessageWriteViewModel
import kr.co.vividnext.sodalive.mypage.MyPageViewModel
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListApi
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListRepository
import kr.co.vividnext.sodalive.mypage.alarm.AlarmListViewModel
import kr.co.vividnext.sodalive.mypage.auth.AuthApi
import kr.co.vividnext.sodalive.mypage.auth.AuthRepository
import kr.co.vividnext.sodalive.mypage.block.BlockMemberViewModel
import kr.co.vividnext.sodalive.mypage.can.CanApi
import kr.co.vividnext.sodalive.mypage.can.CanRepository
import kr.co.vividnext.sodalive.mypage.can.charge.iap.CanChargeIapViewModel
import kr.co.vividnext.sodalive.mypage.can.charge.pg.CanChargePgViewModel
import kr.co.vividnext.sodalive.mypage.can.coupon.CanCouponViewModel
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempRepository
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentTempViewModel
import kr.co.vividnext.sodalive.mypage.can.payment.CanPaymentViewModel
import kr.co.vividnext.sodalive.mypage.can.payment.CanTempApi
import kr.co.vividnext.sodalive.mypage.can.status.CanStatusViewModel
import kr.co.vividnext.sodalive.mypage.profile.ProfileUpdateViewModel
import kr.co.vividnext.sodalive.mypage.profile.nickname.NicknameUpdateViewModel
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagApi
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagRepository
import kr.co.vividnext.sodalive.mypage.profile.tag.MemberTagViewModel
import kr.co.vividnext.sodalive.mypage.service_center.FaqApi
import kr.co.vividnext.sodalive.mypage.service_center.FaqRepository
import kr.co.vividnext.sodalive.mypage.service_center.ServiceCenterViewModel
import kr.co.vividnext.sodalive.network.TokenAuthenticator
import kr.co.vividnext.sodalive.report.ReportApi
import kr.co.vividnext.sodalive.report.ReportRepository
import kr.co.vividnext.sodalive.settings.ContentSettingsViewModel
import kr.co.vividnext.sodalive.settings.SettingsViewModel
import kr.co.vividnext.sodalive.settings.event.EventApi
import kr.co.vividnext.sodalive.settings.event.EventRepository
import kr.co.vividnext.sodalive.settings.event.EventViewModel
import kr.co.vividnext.sodalive.settings.notice.NoticeApi
import kr.co.vividnext.sodalive.settings.notice.NoticeRepository
import kr.co.vividnext.sodalive.settings.notice.NoticeViewModel
import kr.co.vividnext.sodalive.settings.notification.NotificationSettingsViewModel
import kr.co.vividnext.sodalive.settings.signout.SignOutViewModel
import kr.co.vividnext.sodalive.settings.terms.TermsApi
import kr.co.vividnext.sodalive.settings.terms.TermsRepository
import kr.co.vividnext.sodalive.settings.terms.TermsViewModel
import kr.co.vividnext.sodalive.user.UserApi
import kr.co.vividnext.sodalive.user.UserRepository
import kr.co.vividnext.sodalive.user.UserViewModel
import kr.co.vividnext.sodalive.user.find_password.FindPasswordViewModel
import kr.co.vividnext.sodalive.user.login.LoginViewModel
import kr.co.vividnext.sodalive.user.signup.SignUpViewModel
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.core.context.startKoin
import org.koin.dsl.module
import retrofit2.Retrofit
import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit

class AppDI(private val context: Context, isDebugMode: Boolean) {
    private val baseUrl = BuildConfig.BASE_URL

    private val otherModule = module {
        single { GsonBuilder().create() }
        single { ObjectBox(get()) }
    }

    private val networkModule = module {
        single {
            val logging = HttpLoggingInterceptor()

            if (isDebugMode) {
                logging.setLevel(HttpLoggingInterceptor.Level.BODY)
            } else {
                logging.setLevel(HttpLoggingInterceptor.Level.NONE)
            }

            OkHttpClient().newBuilder()
                .addInterceptor(logging)
                .authenticator(TokenAuthenticator(get()))
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .build()
        }

        single {
            Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
                .client(get())
                .build()
        }

        single { ApiBuilder().build(get(), AlarmListApi::class.java) }
        single { ApiBuilder().build(get(), CanApi::class.java) }
        single { ApiBuilder().build(get(), CanTempApi::class.java) }
        single { ApiBuilder().build(get(), AuthApi::class.java) }
        single { ApiBuilder().build(get(), UserApi::class.java) }
        single { ApiBuilder().build(get(), MenuApi::class.java) }
        single { ApiBuilder().build(get(), LiveApi::class.java) }
        single { ApiBuilder().build(get(), TermsApi::class.java) }
        single { ApiBuilder().build(get(), EventApi::class.java) }
        single { ApiBuilder().build(get(), SeriesApi::class.java) }
        single { ApiBuilder().build(get(), ReportApi::class.java) }
        single { ApiBuilder().build(get(), LiveRecommendApi::class.java) }
        single { ApiBuilder().build(get(), ExplorerApi::class.java) }
        single { ApiBuilder().build(get(), MessageApi::class.java) }
        single { ApiBuilder().build(get(), NoticeApi::class.java) }
        single { ApiBuilder().build(get(), AudioContentApi::class.java) }
        single { ApiBuilder().build(get(), FaqApi::class.java) }
        single { ApiBuilder().build(get(), MemberTagApi::class.java) }
        single { ApiBuilder().build(get(), RouletteApi::class.java) }
        single { ApiBuilder().build(get(), CreatorCommunityApi::class.java) }
        single { ApiBuilder().build(get(), CategoryApi::class.java) }
        single { ApiBuilder().build(get(), PlaylistApi::class.java) }
    }

    private val viewModelModule = module {
        viewModel { LoginViewModel(get()) }
        viewModel { SignUpViewModel(get()) }
        viewModel { TermsViewModel(get()) }
        viewModel { FindPasswordViewModel(get()) }
        viewModel { MainViewModel(get(), get(), get(), get()) }
        viewModel { LiveViewModel(get(), get(), get(), get()) }
        viewModel { MyPageViewModel(get(), get()) }
        viewModel { CanStatusViewModel(get()) }
        viewModel { CanChargePgViewModel(get()) }
        viewModel { CanPaymentViewModel(get()) }
        viewModel { CanPaymentTempViewModel(get()) }
        viewModel { LiveRoomDetailViewModel(get()) }
        viewModel { LiveRoomCreateViewModel(get()) }
        viewModel { LiveTagViewModel(get()) }
        viewModel { LiveRoomEditViewModel(get()) }
        viewModel { LiveRoomViewModel(get(), get(), get(), get()) }
        viewModel { LiveRoomDonationMessageViewModel(get()) }
        viewModel { ExplorerViewModel(get()) }
        viewModel { UserProfileViewModel(get(), get(), get()) }
        viewModel { UserFollowerListViewModel(get(), get()) }
        viewModel { TextMessageViewModel(get()) }
        viewModel { TextMessageWriteViewModel(get()) }
        viewModel { VoiceMessageViewModel(get()) }
        viewModel { VoiceMessageWriteViewModel(get()) }
        viewModel { SelectMessageRecipientViewModel(get(), get()) }
        viewModel { NoticeViewModel(get()) }
        viewModel { EventViewModel(get()) }
        viewModel { NotificationSettingsViewModel(get()) }
        viewModel { ContentSettingsViewModel() }
        viewModel { SettingsViewModel(get()) }
        viewModel { SeriesDetailViewModel(get(), get()) }
        viewModel { SeriesListAllViewModel(get()) }
        viewModel { SeriesContentAllViewModel(get()) }
        viewModel { SignOutViewModel(get()) }
        viewModel { TextMessageDetailViewModel(get()) }
        viewModel { LiveReservationStatusViewModel(get()) }
        viewModel { AudioContentMainBannerViewModel(get()) }
        viewModel { AudioContentMainRankingViewModel(get()) }
        viewModel { AudioContentMainCurationViewModel(get()) }
        viewModel { AudioContentMainOrderListViewModel(get()) }
        viewModel { AudioContentMainNewContentViewModel(get()) }
        viewModel { AudioContentMainRecommendSeriesViewModel(get()) }
        viewModel { AudioContentViewModel(get()) }
        viewModel { AudioContentOrderListViewModel(get()) }
        viewModel { AudioContentUploadViewModel(get()) }
        viewModel { AudioContentModifyViewModel(get()) }
        viewModel { AudioContentThemeViewModel(get()) }
        viewModel { AudioContentDetailViewModel(get(), get(), get(), get(), get()) }
        viewModel { AudioContentCommentListViewModel(get()) }
        viewModel { AudioContentCommentReplyViewModel(get()) }
        viewModel { FollowingCreatorViewModel(get(), get()) }
        viewModel { ServiceCenterViewModel(get()) }
        viewModel { ProfileUpdateViewModel(get()) }
        viewModel { NicknameUpdateViewModel(get()) }
        viewModel { MemberTagViewModel(get()) }
        viewModel { UserProfileDonationAllViewModel(get(), get()) }
        viewModel { AudioContentCurationViewModel(get()) }
        viewModel { AudioContentNewAllViewModel(get()) }
        viewModel { AudioContentAllByThemeViewModel(get()) }
        viewModel { AudioContentRankingAllViewModel(get()) }
        viewModel { RouletteSettingsViewModel(get()) }
        viewModel { CreatorCommunityAllViewModel(get(), get()) }
        viewModel { CreatorCommunityCommentListViewModel(get()) }
        viewModel { CreatorCommunityWriteViewModel(get()) }
        viewModel { CreatorCommunityModifyViewModel(get()) }
        viewModel { CanCouponViewModel(get()) }
        viewModel { CanChargeIapViewModel(get()) }
        viewModel { AlarmListViewModel(get()) }
        viewModel { BlockMemberViewModel(get()) }
        viewModel { UserViewModel(get(), get()) }
        viewModel { MenuConfigViewModel(get()) }
        viewModel { AudioContentPlaylistListViewModel(get()) }
        viewModel { AudioContentPlaylistDetailViewModel(get()) }
        viewModel { AudioContentPlaylistCreateViewModel(get()) }
        viewModel { AudioContentPlaylistModifyViewModel(get()) }
    }

    private val repositoryModule = module {
        factory { UserRepository(get()) }
        factory { TermsRepository(get()) }
        factory { SeriesRepository(get()) }
        factory { LiveRepository(get(), get(), get()) }
        factory { EventRepository(get()) }
        factory { LiveRecommendRepository(get()) }
        factory { AuthRepository(get()) }
        factory { CanRepository(get()) }
        factory { CanPaymentTempRepository(get()) }
        factory { LiveTagRepository(get()) }
        factory { ReportRepository(get()) }
        factory { ExplorerRepository(get()) }
        factory { MessageRepository(get()) }
        factory { NoticeRepository(get()) }
        factory { AudioContentRepository(get(), get(), get()) }
        factory { AudioContentCommentRepository(get()) }
        factory { PlaybackTrackingRepository(get()) }
        factory { FollowingCreatorRepository(get()) }
        factory { FaqRepository(get()) }
        factory { MemberTagRepository(get()) }
        factory { UserProfileFantalkAllViewModel(get(), get()) }
        factory { RouletteRepository(get()) }
        factory { CreatorCommunityRepository(get()) }
        factory { AlarmListRepository(get()) }
        factory { MenuConfigRepository(get()) }
        factory { AudioContentPlaylistRepository(get()) }
    }

    private val moduleList = listOf(
        networkModule,
        viewModelModule,
        repositoryModule,
        otherModule
    )

    init {
        startKoin {
            androidContext(context)
            modules(moduleList)
        }
    }
}
