class Location < ApplicationRecord
  validates :postcode, on: :postcode, presence: { message: I18n.t("validations.location.postcode_blank") }
  validate :validate_postcode, on: :postcode, if: proc { |model| model.postcode.presence }
  validates :location_admin_district, on: :location_admin_district, presence: { message: I18n.t("validations.location_admin_district") }
  validates :units, on: :units, presence: { message: I18n.t("validations.location.units") }
  validates :type_of_unit, on: :type_of_unit, presence: { message: I18n.t("validations.location.type_of_unit") }
  validates :mobility_type, on: :mobility_type, presence: { message: I18n.t("validations.location.mobility_standards") }
  validates :startdate, on: :startdate, presence: { message: I18n.t("validations.location.startdate_invalid") }
  validate :validate_startdate, on: :startdate, if: proc { |model| model.startdate.presence }
  validate :validate_confirmed
  belongs_to :scheme
  has_many :lettings_logs, class_name: "LettingsLog"
  has_many :location_deactivation_periods, class_name: "LocationDeactivationPeriod"

  has_paper_trail

  before_save :lookup_postcode!, if: :postcode_changed?

  auto_strip_attributes :name

  scope :search_by_postcode, ->(postcode) { where("REPLACE(postcode, ' ', '') ILIKE ?", "%#{postcode.delete(' ')}%") }
  scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") }
  scope :search_by, ->(param) { search_by_name(param).or(search_by_postcode(param)) }
  scope :started, -> { where("startdate <= ?", Time.zone.today).or(where(startdate: nil)) }
  scope :active, -> { where(confirmed: true).and(started) }

  LOCAL_AUTHORITIES = {
    "E07000223": "Adur",
    "E07000026": "Allerdale",
    "E07000032": "Amber Valley",
    "E07000224": "Arun",
    "E07000170": "Ashfield",
    "E07000105": "Ashford",
    "E07000200": "Babergh",
    "E09000002": "Barking and Dagenham",
    "E09000003": "Barnet",
    "E08000016": "Barnsley",
    "E07000027": "Barrow-in-Furness",
    "E07000066": "Basildon",
    "E07000084": "Basingstoke and Deane",
    "E07000171": "Bassetlaw",
    "E06000022": "Bath and North East Somerset",
    "E06000055": "Bedford",
    "E09000004": "Bexley",
    "E08000025": "Birmingham",
    "E07000129": "Blaby",
    "E06000008": "Blackburn with Darwen",
    "E06000009": "Blackpool",
    "E07000033": "Bolsover",
    "E08000001": "Bolton",
    "E07000136": "Boston",
    "E06000058": "Bournemouth, Christchurch and Poole",
    "E06000036": "Bracknell Forest",
    "E08000032": "Bradford",
    "E07000067": "Braintree",
    "E07000143": "Breckland",
    "E09000005": "Brent",
    "E07000068": "Brentwood",
    "E06000043": "Brighton and Hove",
    "E06000023": "Bristol, City of",
    "E07000144": "Broadland",
    "E09000006": "Bromley",
    "E07000234": "Bromsgrove",
    "E07000095": "Broxbourne",
    "E07000172": "Broxtowe",
    "E06000060": "Buckinghamshire",
    "E07000117": "Burnley",
    "E08000002": "Bury",
    "E08000033": "Calderdale",
    "E07000008": "Cambridge",
    "E09000007": "Camden",
    "E07000192": "Cannock Chase",
    "E07000106": "Canterbury",
    "E07000028": "Carlisle",
    "E07000069": "Castle Point",
    "E06000056": "Central Bedfordshire",
    "E07000130": "Charnwood",
    "E07000070": "Chelmsford",
    "E07000078": "Cheltenham",
    "E07000177": "Cherwell",
    "E06000049": "Cheshire East",
    "E06000050": "Cheshire West and Chester",
    "E07000034": "Chesterfield",
    "E07000225": "Chichester",
    "E07000118": "Chorley",
    "E09000001": "City of London",
    "E07000071": "Colchester",
    "E07000029": "Copeland",
    "E07000150": "Corby",
    "E06000052": "Cornwall",
    "E07000079": "Cotswold",
    "E06000047": "County Durham",
    "E08000026": "Coventry",
    "E07000163": "Craven",
    "E07000226": "Crawley",
    "E09000008": "Croydon",
    "E07000096": "Dacorum",
    "E06000005": "Darlington",
    "E07000107": "Dartford",
    "E07000151": "Daventry",
    "E06000015": "Derby",
    "E07000035": "Derbyshire Dales",
    "E08000017": "Doncaster",
    "E06000059": "Dorset",
    "E07000108": "Dover",
    "E08000027": "Dudley",
    "E09000009": "Ealing",
    "E07000009": "East Cambridgeshire",
    "E07000040": "East Devon",
    "E07000085": "East Hampshire",
    "E07000242": "East Hertfordshire",
    "E07000137": "East Lindsey",
    "E07000152": "East Northamptonshire",
    "E06000011": "East Riding of Yorkshire",
    "E07000193": "East Staffordshire",
    "E07000244": "East Suffolk",
    "E07000061": "Eastbourne",
    "E07000086": "Eastleigh",
    "E07000030": "Eden",
    "E07000207": "Elmbridge",
    "E09000010": "Enfield",
    "E07000072": "Epping Forest",
    "E07000208": "Epsom and Ewell",
    "E07000036": "Erewash",
    "E07000041": "Exeter",
    "E07000087": "Fareham",
    "E07000010": "Fenland",
    "E07000112": "Folkestone and Hythe",
    "E07000080": "Forest of Dean",
    "E07000119": "Fylde",
    "E08000037": "Gateshead",
    "E07000173": "Gedling",
    "E07000081": "Gloucester",
    "E07000088": "Gosport",
    "E07000109": "Gravesham",
    "E07000145": "Great Yarmouth",
    "E09000011": "Greenwich",
    "E07000209": "Guildford",
    "W06000002": "Gwynedd",
    "E09000012": "Hackney",
    "E06000006": "Halton",
    "E07000164": "Hambleton",
    "E09000013": "Hammersmith and Fulham",
    "E07000131": "Harborough",
    "E09000014": "Haringey",
    "E07000073": "Harlow",
    "E07000165": "Harrogate",
    "E09000015": "Harrow",
    "E07000089": "Hart",
    "E06000001": "Hartlepool",
    "E07000062": "Hastings",
    "E07000090": "Havant",
    "E09000016": "Havering",
    "E06000019": "Herefordshire, County of",
    "E07000098": "Hertsmere",
    "E07000037": "High Peak",
    "S12000017": "Highland",
    "E09000017": "Hillingdon",
    "E07000132": "Hinckley and Bosworth",
    "E07000227": "Horsham",
    "E09000018": "Hounslow",
    "E07000011": "Huntingdonshire",
    "E07000120": "Hyndburn",
    "E07000202": "Ipswich",
    "E06000046": "Isle of Wight",
    "E06000053": "Isles of Scilly",
    "E09000019": "Islington",
    "E09000020": "Kensington and Chelsea",
    "E07000153": "Kettering",
    "E07000146": "King’s Lynn and West Norfolk",
    "E06000010": "Kingston upon Hull, City of",
    "E09000021": "Kingston upon Thames",
    "E08000034": "Kirklees",
    "E08000011": "Knowsley",
    "E09000022": "Lambeth",
    "E07000121": "Lancaster",
    "E08000035": "Leeds",
    "E06000016": "Leicester",
    "E07000063": "Lewes",
    "E09000023": "Lewisham",
    "E07000194": "Lichfield",
    "E07000138": "Lincoln",
    "E08000012": "Liverpool",
    "E06000032": "Luton",
    "E07000110": "Maidstone",
    "E07000074": "Maldon",
    "E07000235": "Malvern Hills",
    "E08000003": "Manchester",
    "E07000174": "Mansfield",
    "E06000035": "Medway",
    "E07000133": "Melton",
    "E07000187": "Mendip",
    "E09000024": "Merton",
    "E07000042": "Mid Devon",
    "E07000203": "Mid Suffolk",
    "E07000228": "Mid Sussex",
    "E06000002": "Middlesbrough",
    "E06000042": "Milton Keynes",
    "E07000210": "Mole Valley",
    "E07000091": "New Forest",
    "E07000175": "Newark and Sherwood",
    "E08000021": "Newcastle upon Tyne",
    "E07000195": "Newcastle-under-Lyme",
    "E09000025": "Newham",
    "E07000043": "North Devon",
    "E07000038": "North East Derbyshire",
    "E06000012": "North East Lincolnshire",
    "E07000099": "North Hertfordshire",
    "E07000139": "North Kesteven",
    "E06000013": "North Lincolnshire",
    "E07000147": "North Norfolk",
    "E06000024": "North Somerset",
    "E08000022": "North Tyneside",
    "E07000218": "North Warwickshire",
    "E07000134": "North West Leicestershire",
    "E07000154": "Northampton",
    "E06000057": "Northumberland",
    "E07000148": "Norwich",
    "E06000018": "Nottingham",
    "E07000219": "Nuneaton and Bedworth",
    "E07000135": "Oadby and Wigston",
    "E08000004": "Oldham",
    "E07000178": "Oxford",
    "E07000122": "Pendle",
    "E06000031": "Peterborough",
    "E06000026": "Plymouth",
    "E06000044": "Portsmouth",
    "E07000123": "Preston",
    "E06000038": "Reading",
    "E09000026": "Redbridge",
    "E06000003": "Redcar and Cleveland",
    "E07000236": "Redditch",
    "E07000211": "Reigate and Banstead",
    "E07000124": "Ribble Valley",
    "E09000027": "Richmond upon Thames",
    "E07000166": "Richmondshire",
    "E08000005": "Rochdale",
    "E07000075": "Rochford",
    "E07000125": "Rossendale",
    "E07000064": "Rother",
    "E08000018": "Rotherham",
    "E07000220": "Rugby",
    "E07000212": "Runnymede",
    "E07000176": "Rushcliffe",
    "E07000092": "Rushmoor",
    "E06000017": "Rutland",
    "E07000167": "Ryedale",
    "E08000006": "Salford",
    "E08000028": "Sandwell",
    "E07000168": "Scarborough",
    "E07000188": "Sedgemoor",
    "E08000014": "Sefton",
    "E07000169": "Selby",
    "E07000111": "Sevenoaks",
    "E08000019": "Sheffield",
    "E06000051": "Shropshire",
    "E06000039": "Slough",
    "E08000029": "Solihull",
    "E07000246": "Somerset West and Taunton",
    "E07000012": "South Cambridgeshire",
    "E07000039": "South Derbyshire",
    "E06000025": "South Gloucestershire",
    "E07000044": "South Hams",
    "E07000140": "South Holland",
    "E07000141": "South Kesteven",
    "E07000031": "South Lakeland",
    "E07000149": "South Norfolk",
    "E07000155": "South Northamptonshire",
    "E07000179": "South Oxfordshire",
    "E07000126": "South Ribble",
    "E07000189": "South Somerset",
    "E07000196": "South Staffordshire",
    "E08000023": "South Tyneside",
    "E06000045": "Southampton",
    "E06000033": "Southend-on-Sea",
    "E09000028": "Southwark",
    "E07000213": "Spelthorne",
    "E07000240": "St Albans",
    "E08000013": "St. Helens",
    "E07000197": "Stafford",
    "E07000198": "Staffordshire Moorlands",
    "E07000243": "Stevenage",
    "E08000007": "Stockport",
    "E06000004": "Stockton-on-Tees",
    "E06000021": "Stoke-on-Trent",
    "E07000221": "Stratford-on-Avon",
    "E07000082": "Stroud",
    "E08000024": "Sunderland",
    "E07000214": "Surrey Heath",
    "E09000029": "Sutton",
    "E07000113": "Swale",
    "E06000030": "Swindon",
    "E08000008": "Tameside",
    "E07000199": "Tamworth",
    "E07000215": "Tandridge",
    "E07000045": "Teignbridge",
    "E06000020": "Telford and Wrekin",
    "E07000076": "Tendring",
    "E07000093": "Test Valley",
    "E07000083": "Tewkesbury",
    "E07000114": "Thanet",
    "E07000102": "Three Rivers",
    "E06000034": "Thurrock",
    "E07000115": "Tonbridge and Malling",
    "E06000027": "Torbay",
    "E07000046": "Torridge",
    "E09000030": "Tower Hamlets",
    "E08000009": "Trafford",
    "E07000116": "Tunbridge Wells",
    "E07000077": "Uttlesford",
    "E07000180": "Vale of White Horse",
    "E08000036": "Wakefield",
    "E08000030": "Walsall",
    "E09000031": "Waltham Forest",
    "E09000032": "Wandsworth",
    "E06000007": "Warrington",
    "E07000222": "Warwick",
    "E07000103": "Watford",
    "E07000216": "Waverley",
    "E07000065": "Wealden",
    "E07000156": "Wellingborough",
    "E07000241": "Welwyn Hatfield",
    "E06000037": "West Berkshire",
    "E07000047": "West Devon",
    "E07000127": "West Lancashire",
    "E07000142": "West Lindsey",
    "E07000181": "West Oxfordshire",
    "E07000245": "West Suffolk",
    "E09000033": "Westminster",
    "E08000010": "Wigan",
    "E06000054": "Wiltshire",
    "E07000094": "Winchester",
    "E06000040": "Windsor and Maidenhead",
    "E08000015": "Wirral",
    "E07000217": "Woking",
    "E06000041": "Wokingham",
    "E08000031": "Wolverhampton",
    "E07000237": "Worcester",
    "E07000229": "Worthing",
    "E07000238": "Wychavon",
    "E07000128": "Wyre",
    "E07000239": "Wyre Forest",
    "E06000014": "York",
  }.freeze

  enum local_authorities: LOCAL_AUTHORITIES

  MOBILITY_TYPE = {
    "Wheelchair-user standard": "W",
    "Fitted with equipment and adaptations": "A",
    "Property designed to accessible general standard": "M",
    "None": "N",
    "Missing": "X",
  }.freeze

  enum mobility_type: MOBILITY_TYPE

  TYPE_OF_UNIT = {
    "Bungalow": 6,
    "Self-contained flat or bedsit": 1,
    "Self-contained flat or bedsit with common facilities": 2,
    "Self-contained house": 7,
    "Shared flat": 3,
    "Shared house or hostel": 4,
  }.freeze

  enum type_of_unit: TYPE_OF_UNIT

  def postcode=(postcode)
    if postcode
      super UKPostcode.parse(postcode).to_s
    else
      super nil
    end
  end

  def available_from
    return startdate if startdate.present?

    FormHandler.instance.collection_start_date(created_at)
  end

  def open_deactivation
    location_deactivation_periods.deactivations_without_reactivation.first
  end

  def recent_deactivation
    location_deactivation_periods.order("created_at").last
  end

  def status
    @status ||= status_at(Time.zone.now)
  end

  def status_at(date)
    return :incomplete unless confirmed
    return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date
    return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date
    return :reactivating_soon if recent_deactivation&.reactivation_date.present? && date < recent_deactivation.reactivation_date
    return :activating_soon if startdate.present? && date < startdate

    :active
  end

  def active?
    status == :active
  end

  def deactivated?
    status == :deactivated
  end

  def reactivating_soon?
    status == :reactivating_soon
  end

  def validate_postcode
    if !postcode&.match(POSTCODE_REGEXP)
      error_message = I18n.t("validations.postcode")
      errors.add :postcode, error_message
    else
      self.postcode = PostcodeService.clean(postcode)
      if postcode_changed?
        self.location_admin_district = nil
        self.location_code = nil
      end
    end
  end

  def validate_startdate
    unless startdate.between?(scheme.available_from, Time.zone.local(2200, 1, 1))
      error_message = I18n.t("validations.location.startdate_out_of_range", date: scheme.available_from.to_formatted_s(:govuk_date))
      errors.add :startdate, error_message
    end
  end

  def validate_confirmed
    self.confirmed = [postcode, location_admin_district, location_code, units, type_of_unit, mobility_type].all?(&:present?)
  end

private

  PIO = PostcodeService.new

  def lookup_postcode!
    result = PIO.lookup(postcode)
    if result
      self.location_code = result[:location_code]
      self.location_admin_district = result[:location_admin_district]
    end
  end
end