import copy
import json
import re
from crispy_forms.bootstrap import InlineField
from crispy_forms.helper import FormHelper
from crispy_forms import layout as crispy
from crispy_forms import bootstrap as twbscrispy
from corehq.apps.style import crispy as hqcrispy
from django.core.urlresolvers import reverse
from django.template.loader import render_to_string
from datetime import timedelta, datetime, time, date
from django.conf import settings
from django.core.exceptions import ValidationError
from django.forms.fields import *
from django.forms.forms import Form
from django import forms
from django.forms import Field, Widget
from corehq.apps.accounting.utils import domain_is_on_trial
from corehq.apps.casegroups.models import CommCareCaseGroup
from corehq.apps.casegroups.dbaccessors import get_case_groups_in_domain
from corehq.apps.locations.models import SQLLocation
from corehq.apps.locations.util import get_locations_from_ids
from corehq.apps.reminders.event_handlers import TRIAL_MAX_EMAILS
from corehq.apps.reminders.util import DotExpandedDict, get_form_list
from corehq.apps.groups.models import Group
from corehq.apps.hqwebapp.crispy import ErrorsOnlyField
from corehq.apps.style.crispy import FieldWithHelpBubble, B3MultiField
from corehq.apps.users.forms import SupplyPointSelectWidget
from corehq import toggles
from corehq.util.timezones.conversions import UserTime
from dimagi.utils.couch.database import iter_docs
from dimagi.utils.decorators.memoized import memoized
from .models import (
    REPEAT_SCHEDULE_INDEFINITELY,
    CaseReminderEvent,
    RECIPIENT_USER,
    RECIPIENT_CASE,
    RECIPIENT_SURVEY_SAMPLE,
    RECIPIENT_OWNER,
    RECIPIENT_LOCATION,
    MATCH_EXACT,
    MATCH_REGEX,
    MATCH_ANY_VALUE,
    EVENT_AS_SCHEDULE,
    EVENT_AS_OFFSET,
    CaseReminderHandler,
    FIRE_TIME_DEFAULT,
    FIRE_TIME_CASE_PROPERTY,
    METHOD_SMS,
    METHOD_SMS_CALLBACK,
    METHOD_SMS_SURVEY,
    METHOD_IVR_SURVEY,
    METHOD_EMAIL,
    CASE_CRITERIA,
    QUESTION_RETRY_CHOICES,
    SurveyKeyword,
    RECIPIENT_PARENT_CASE,
    RECIPIENT_SUBCASE,
    FIRE_TIME_RANDOM,
    SEND_NOW,
    SEND_LATER,
    RECIPIENT_USER_GROUP,
    UI_SIMPLE_FIXED,
    UI_COMPLEX,
    RECIPIENT_ALL_SUBCASES,
    RECIPIENT_CASE_OWNER_LOCATION_PARENT,
    DAY_MON,
    DAY_TUE,
    DAY_WED,
    DAY_THU,
    DAY_FRI,
    DAY_SAT,
    DAY_SUN,
    DAY_ANY,
)
from dateutil.parser import parse
from django.utils.translation import ugettext as _, ugettext_noop, ugettext_lazy
from corehq.apps.app_manager.models import Form as CCHQForm
from dimagi.utils.django.fields import TrimmedCharField
from corehq.util.timezones.utils import get_timezone_for_user
from langcodes import get_name as get_language_name

ONE_MINUTE_OFFSET = time(0, 1)

NO_RESPONSE = "none"

YES_OR_NO = (
    ("Y", ugettext_lazy("Yes")),
    ("N", ugettext_lazy("No")),
)

NOW_OR_LATER = (
    (SEND_NOW, ugettext_lazy("Now")),
    (SEND_LATER, ugettext_lazy("Later")),
)

CONTENT_CHOICES = (
    (METHOD_SMS, ugettext_lazy("SMS")),
    (METHOD_SMS_SURVEY, ugettext_lazy("SMS Survey")),
)

KEYWORD_CONTENT_CHOICES = (
    (METHOD_SMS, ugettext_lazy("SMS")),
    (METHOD_SMS_SURVEY, ugettext_lazy("SMS Survey")),
    (NO_RESPONSE, ugettext_lazy("No Response")),
)

KEYWORD_RECIPIENT_CHOICES = (
    (RECIPIENT_USER_GROUP, ugettext_lazy("Mobile Worker Group")),
    (RECIPIENT_OWNER, ugettext_lazy("The case's owner")),
)

ONE_TIME_RECIPIENT_CHOICES = (
    (RECIPIENT_USER_GROUP, ugettext_lazy("Mobile Worker Group")),
    (RECIPIENT_SURVEY_SAMPLE, ugettext_lazy("Case Group")),
)

EVENT_CHOICES = (
    (EVENT_AS_OFFSET, ugettext_lazy("Offset-based")),
    (EVENT_AS_SCHEDULE, ugettext_lazy("Schedule-based"))
)

EMAIL_TRIAL_MESSAGE = ugettext_lazy("You are currently on a trial plan. "
    "You are allowed to send %(limit)s reminder emails after which you will "
    "not be able to send anymore reminder emails unless you upgrade your "
    "plan.")


def add_field_choices(form, field_name, choice_tuples):
    choices = copy.copy(form.fields[field_name].choices)
    choices.extend(choice_tuples)
    form.fields[field_name].choices = choices


def user_group_choices(domain):
    ids = Group.ids_by_domain(domain)
    return [(doc['_id'], doc['name'])
            for doc in iter_docs(Group.get_db(), ids)]


def case_group_choices(domain):
    return [(group._id, group.name)
            for group in get_case_groups_in_domain(domain)]


def form_choices(domain):
    available_forms = get_form_list(domain)
    return [(form['code'], form['name']) for form in available_forms]


def validate_integer(value, error_msg, nonnegative=False):
    try:
        assert value is not None
        value = int(value)
        if nonnegative:
            assert value >= 0
        return value
    except (ValueError, AssertionError):
        raise ValidationError(error_msg)


def validate_date(value):
    date_regex = re.compile('^\d\d\d\d-\d\d-\d\d$')
    if not isinstance(value, basestring) or date_regex.match(value) is None:
        raise ValidationError(_('Dates must be in YYYY-MM-DD format.'))
    try:
        return parse(value).date()
    except Exception:
        raise ValidationError(_('Invalid date given.'))


def validate_time(value):
    if isinstance(value, time):
        return value
    error_msg = _("Please enter a valid time from 00:00 to 23:59.")
    time_regex = re.compile("^\d{1,2}:\d\d(:\d\d){0,1}$")
    if not isinstance(value, basestring) or time_regex.match(value) is None:
        raise ValidationError(error_msg)
    try:
        return parse(value).time()
    except Exception:
        raise ValidationError(error_msg)


def validate_form_unique_id(form_unique_id, domain):
    error_msg = _('Invalid form chosen.')
    try:
        form = CCHQForm.get_form(form_unique_id)
        app = form.get_app()
    except Exception:
        raise ValidationError(error_msg)

    if app.d
omain != domain:
        raise ValidationError(error_msg)

    return form_unique_id


def clean_group_id(group_id, expected_domain):
    error_msg = _('Invalid selection.')
    if not group_id:
        raise ValidationError(error_msg)

    try:
        
group = Group.get(group_id)
    except Exception:
        raise ValidationError(error_msg)

    if group.doc_type != 'Group' or group.domain != expected_domain:
        raise ValidationError(error_msg)

    return group_id


def clean_case_group_id(group_id, expected_domain):
    error_msg = _('Invalid selection.')
    if not group_id:
        raise ValidationError(error_msg)

    try:
        group = CommCareCaseGroup.get(group_id)
    except Exception:
        raise ValidationError(error_msg)

    if group.doc_type != 'CommCareCaseGroup' or group.domain != expected_domain:
        raise ValidationError(error_msg)

    return group_id


MATCH_TYPE_CHOICES = (
    (MATCH_ANY_VALUE, ugettext_noop("exists.")),
    (MATCH_EXACT, ugettext_noop("equals")),
    (MATCH_REGEX, ugettext_noop("matches regular expression")),
)

START_REMINDER_ALL_CASES = 'start_all_cases'
START_REMINDER_ON_CASE_DATE = 'case_date'
START_REMINDER_ON_CASE_PROPERTY = 'case_property'
START_REMINDER_ON_DAY_OF_WEEK = 'day_of_week'

START_DATE_OFFSET_BEFORE = 'offset_before'
START_DATE_OFFSET_AFTER = 'offset_after'

START_PROPERTY_OFFSET_DELAY = 'offset_delay'
START_PROPERTY_OFFSET_IMMEDIATE = 'offset_immediate'

START_PROPERTY_ALL_CASES_VALUE = '_id'

EVENT_TIMING_IMMEDIATE = 'immediate'

REPEAT_TYPE_NO = 'no_repeat'
REPEAT_TYPE_INDEFINITE = 'indefinite'
REPEAT_TYPE_SPECIFIC = 'specific'

STOP_CONDITION_CASE_PROPERTY = 'case_property'


class BaseScheduleCaseReminderForm(forms.Form):
    """
    This form creates a new CaseReminder. It is the most basic version, no advanced options (like language).
    """
    nickname = forms.CharField(
        label=ugettext_noop("Name"),
        error_messages={
            'required': ugettext_noop("Please enter a name for this reminder."),
        }
    )

    # Fieldset: Send Options
    # simple has start_condition_type = CASE_CRITERIA by default
    case_type = forms.CharField(
        required=False,
        label=ugettext_noop("Send For Case Type"),
    )
    start_reminder_on = forms