

import 'package:app_hit_a_wod/src/models/array_response.model.dart';
import 'package:app_hit_a_wod/src/models/box_order.model.dart';
import 'package:app_hit_a_wod/src/models/pricing.model.dart';
import 'package:app_hit_a_wod/src/models/stripe_user.model.dart';
import 'package:app_hit_a_wod/src/models/subscription_selection.model.dart';
import 'package:app_hit_a_wod/src/models/user_subscription.model.dart';
import 'package:app_hit_a_wod/src/providers/api.provider.dart';
import 'package:app_hit_a_wod/src/providers/auth.provider.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:rxdart/rxdart.dart';

class ChangePricingFormBloc {
  
  BuildContext _context;
  ApiProvider _api;
  StripeUser _stripeUser;
  SubscriptionSelection _ss;

  BehaviorSubject<String> _statusSubject = new BehaviorSubject(); //'init', 'loading', 'done', 'loading_pricings'
  Stream<String> get statusStream => _statusSubject.stream;
  BehaviorSubject<Pricing> _pricingSelected = new BehaviorSubject();
  Stream<Pricing> get pricingSelectedStream => _pricingSelected.stream;
  get setPricing => _pricingSelected.sink.add;
  BehaviorSubject<bool> _overrideSubject = new BehaviorSubject();
  Stream<bool> get overrideStream => _overrideSubject.stream;
  get setOverride => _overrideSubject.sink.add;
  BehaviorSubject<bool> _automaticSubject = new BehaviorSubject();
  Stream<bool> get automaticStream => _automaticSubject.stream;
  get setAutomatic => _automaticSubject.sink.add;
  BehaviorSubject<List<Pricing>> _pricingsSubject = new BehaviorSubject();
  Stream<List<Pricing>> get pricingsStream => _pricingsSubject.stream;

  ChangePricingFormBloc(BuildContext this._context, ApiProvider this._api, StripeUser this._stripeUser, SubscriptionSelection this._ss, { bool automatic = false, bool selectCurrentSubscription = false }) {
    setAutomatic(automatic);
    
    if(selectCurrentSubscription) setPricing(_ss.pricing);
    else setPricing(null);

    setOverride(false);

    _loadPricings(!selectCurrentSubscription);    
  }

  _loadPricings(bool avoidCurrent) async {
    _statusSubject.sink.add("loading_pricings");
    ArrayResponse<Pricing> resp = await _api.getBoxPricings(_ss.box.id, params: {"is_public": true});
    List<Pricing> pricings = resp.data;

    //hem de treure l'actual
    if(avoidCurrent) {
      pricings = pricings.where((Pricing p) => _ss.pricing.id!=p.id).toList();
    }

    _pricingsSubject.sink.add(pricings);
    _statusSubject.sink.add('init');
  }

  changePricing() async {
    if(_pricingSelected.value==null) _statusSubject.sink.addError("Selecciona una tarifa.");
    else {
      _statusSubject.sink.add('loading');
      try {
        final int box_id = _ss.box.id;
        final DateTime start_date = _overrideSubject.value ? DateTime.now() : _ss.us.end_date;

        //1. Crear comanda i altres
        var resp = await _api.renewUserSubscription(_ss.us.id, {
          "pricing_id": _pricingSelected.value.id,
          "role": _ss.role.id,
          "user_id": _ss.us.user_id,
          "renew": _automaticSubject.value ? 1 : 0,
          "start_date": DateFormat("yyyy-MM-dd").format(start_date),
          "payment_type_id": 1, //stripe
          "override": _overrideSubject.value ? 1 : 0,
          "box_id": box_id
        });

        //2. Pagar
        final String msg = resp[0];
        final UserSubscription us = UserSubscription.fromJson(resp[1]);
        final BoxOrder bo = BoxOrder.fromJson(resp[2]);
        var resp2 = await _api.payUserSubscription(us.id, {
          "start_date": DateFormat("yyyy-MM-dd HH:mm:ss").format(start_date),
          "box_id": box_id,
          "payment_type_slug": "stripe"
        });

        final auth = Provider.of<AuthProvider>(_context, listen: false);
        auth.refreshToken();
        Navigator.pop(_context);

      } on DioError catch(e) {
        _statusSubject.sink.add('init');
        _statusSubject.sink.addError(e.response!=null ? e.response.data["error"] : e.toString());
        return false;
      } on Exception catch(e) {
        _statusSubject.sink.add('init');
        _statusSubject.sink.addError(e.toString());
        return false;
      }
    }
  }

}